올바른 방법보다 인터페이스에 더 많은 것이 있습니까?


159

따라서이 인터페이스가 있다고 가정 해 보겠습니다.

public interface IBox
{
   public void setSize(int size);
   public int getSize();
   public int getArea();
  //...and so on
}

그리고 그것을 구현하는 클래스가 있습니다.

public class Rectangle implements IBox
{
   private int size;
   //Methods here
}

인터페이스 IBox를 사용하려면 실제로 다음과 같은 방식으로 인스턴스를 만들 수 없습니다.

public static void main(String args[])
{
    Ibox myBox=new Ibox();
}

권리? 따라서 실제로이 작업을 수행해야합니다.

public static void main(String args[])
{
    Rectangle myBox=new Rectangle();
}

그것이 사실이라면, 인터페이스의 유일한 목적은 인터페이스를 구현하는 클래스가 인터페이스에 설명 된대로 올바른 메소드를 가지고 있는지 확인하는 것입니다. 아니면 다른 인터페이스 사용이 있습니까?


2
인터페이스는 Java에만 국한되지 않습니다. 모든 OOP 언어는 자바처럼 명시 적으로 정의 된 것은 아니지만 어떤 형태로든 다른 형태로되어 있습니다.
Herms 2019

2
기술적으로 모든 강력한 형식의 OOP 언어는 어떤 형태로든 다른 언어로되어 있습니다. 유형이 지정되지 않은 오리 언어는 비슷한 개념이 없습니다.
Jared

1
@Jared 강력한 타이핑을 정적 타이핑과 혼동하지 않고 동적으로 타이핑 한 "타이핑되지 않은"것과 혼동하지 않습니까?
eljenso

다형성은 인터페이스를 통해서도 달성 될 수 있습니다. 이 페이지의 마지막 섹션을 확인하십시오 codenuggets.com/2014/06/20/java-interface
Jeff

답변:


143

인터페이스는 코드를보다 유연하게 만드는 방법입니다. 당신이하는 일은 이것입니다 :

Ibox myBox=new Rectangle();

그런 다음 나중에 다른 종류의 상자를 사용하려는 경우 (더 나은 종류의 상자가있는 다른 라이브러리가있을 수 있음) 코드를 다음으로 전환하십시오.

Ibox myBox=new OtherKindOfBox();

일단 익숙해지면 훌륭한 (실제로 필수적인) 작업 방법을 찾을 수 있습니다.

다른 이유는 예를 들어 상자 목록을 만들고 각 상자에 대해 일부 작업을 수행하려고하지만 목록에 다른 종류의 상자를 포함시키려는 경우입니다. 각 상자에서 다음을 수행 할 수 있습니다.

myBox.close()

(IBox에 close () 메소드가 있다고 가정) 실제 myBox 클래스는 반복중인 상자에 따라 변경됩니다.


54
이 답변에는 Java 인터페이스 에만 적용되는 내용이 없습니다 . 추상 클래스 또는 구체적인 클래스에도 동일하게 적용됩니다. 여러 인터페이스 를 구현할 수있는 기능 과 그것이 유용한시기 / 이유 를 언급하면 ​​좋은 답변을 기대할 수 있습니다.
Rogério

16
이것이 어떻게 대답으로 선정 되었습니까? 왜 다형성이 유용한 지에 대한 간단한 설명이지만, 위의 포스터가 말했듯이 여러 인터페이스에 대한 더 나은 설명을 기대할 것입니다. 인터페이스 대 추상 클래스를 사용하는 것이 적절한 경우 더 중요합니다.
trevorkavanaugh

2
이것은 인터페이스와 다형성의 기본과 관련된 모든 것을 설명하는 것과는 거의 관련이 없습니다.
A-Developer-Has-No-Name

123

인터페이스를 유용하게 만드는 것은 "마음을 바꾸고 나중에 다른 구현을 사용할 수 있으며 개체가 생성 된 한 곳만 변경하면된다"는 사실 이 아닙니다 . 그것은 문제가 아닙니다.

실제 요점은 이미 이름입니다. 모든 사람이 해당 인터페이스에서 작동하는 모든 코드를 사용하도록 구현할 수 있는 인터페이스 를 정의합니다 . 가장 좋은 예는 다음 java.util.Collections과 같은 인터페이스에만 작동 유용한 방법 온갖 제공하는 sort()reverse()를 들어 List. 여기서 중요한 점은이 코드는 지금 정렬하거나 반대로 사용할 수 있다는 어떤 클래스가 구현하는 List인터페이스 - 단지 ArrayListLinkedList뿐만 아니라 당신이하는 방식으로 구현 될 수있는, 자신을 작성하는 것이 클래스 쓴 사람들이 java.util.Collections상상하지 않았다.

같은 방식으로 잘 알려진 인터페이스 또는 사용자가 정의한 인터페이스에서 작동하는 코드를 작성할 수 있으며 다른 사람들이 클래스를 지원하도록 요청하지 않고도 코드를 사용할 수 있습니다.

인터페이스의 또 다른 일반적인 용도는 콜백입니다. 예를 들어, java.swing.table.TableCellRenderer 는 Swing 테이블이 특정 열의 데이터를 표시하는 방법에 영향을 줄 수 있습니다. 해당 인터페이스를 구현하고 인스턴스를에 전달 JTable하면 테이블을 렌더링하는 동안 어느 시점에서 코드가 해당 작업을 수행하도록 호출됩니다.


9
당신은 자바 패키지 클래스에서 예를 주었을 때 그게처럼, 나는 꽤 좋은 대답이다 ...
Owais 쿠 레시

1
내가 좋아하는you can write code that operates on well-known interfaces, or interfaces you define
Manish Kumar

잠깐만 ... 인터페이스를 유용하게 만드는 것은 [원하는 구현을 사용하는 능력]이 아니라 [원하는 구현을 사용하는 능력]인가? 반대의 경우를 언급 하는 것은 꽤 좋은 지적입니다.
Powerslave

4
@Powerslave : 인터페이스를 더 유용하게 만드는 것은 [임시를 변경할 때 한 줄만 변경하면되는 코드를 작성하는 기능]이 아니라 [구현을 명시하지 않은 코드를 작성하는 기능] 모두].
Michael Borgwardt

@MichaelBorgwardt 그것은 더 나은 소리. :) 설명해 주셔서 감사합니다!
Powerslave

119

내가 읽은 많은 용도 중 하나는 Java에서 다중 상속 사용 인터페이스가 없으면 어려운 곳입니다.

class Animal
{
void walk() { } 
....
.... //other methods and finally
void chew() { } //concentrate on this
} 

이제 다음과 같은 경우를 상상해보십시오.

class Reptile extends Animal 
{ 
//reptile specific code here
} //not a problem here

그러나,

class Bird extends Animal
{
...... //other Bird specific code
} //now Birds cannot chew so this would a problem in the sense Bird classes can also call chew() method which is unwanted

더 나은 디자인은 다음과 같습니다.

class Animal
{
void walk() { } 
....
.... //other methods 
} 

Animal은 chew () 메소드를 가지고 있지 않으며 대신 다음과 같은 인터페이스에 배치됩니다.

interface Chewable {
void chew();
}

그리고 파충류 클래스가 새가 아닌 이것을 구현하도록하십시오 (조류는 씹을 수 없기 때문에).

class Reptile extends Animal implements Chewable { } 

새의 경우 :

class Bird extends Animal { }

6
@CHEBURASHKA 그리고 나쁜 이름. Reptile"씹는" 경우 , 그 자체가 아닌 "씹을 수있는"것입니다. (때때로) 명명 인터페이스의 규칙은 무엇이든 완벽하게 이해되는 경우에만 적용해야합니다. Predator여기서 인터페이스 이름을 지정하는 것이 더 적절할 것입니다.
Powerslave

6
@Powerslave 맞다. 파충류는 "씹을 수있다"/ "씹을 수있다". 매는 포식자이지만 여전히 씹을 수는 없습니다. 단지 nitpicking이지만 "chewable"은 인터페이스의 문서에서 더 잘 정의 될 수 있습니다.
Madmenyo

훌륭합니다. 아주 잘 설명했습니다. 감사합니다..!
Gurusinghe

1
나는 그것을 얻지 못한다. 인터페이스가 구현하는 각 클래스에서 동일한 메소드를 구현할 수있는 좋은 방법 인 것 같습니다. 예를 들어 run () 및 Dog 클래스를 사용하여 Bird 클래스를 바보로 선택할 수 없습니다. runn ()-모두 동일합니다). 그러나주의를 기울이고 클래스가 동일한 메소드 형식 / 구조를 갖도록 하여이 같은 것을 달성 할 수 없었습니까? 실제로 인터페이스는 프로그래머가 잊어 버리지 않도록하는 것처럼 보입니다. 또한 인터페이스는 시간을 절약하지 못하는 것 같습니다. 나는 여전히 그것을 구현하는 각 클래스에서 메소드를 정의해야합니다.
Alex G

@ AlexG-나는 많은 사용 친구 중 하나를 말했다 :) 더있다, 우리는 간단한 방식으로 질문에 대답하기 위해 표면을 간신히 긁었다!
peevesy

47

인터페이스의 목적은 다형성 , 일명 유형 대체 입니다. 예를 들어 다음과 같은 방법이 있습니다.

public void scale(IBox b, int i) {
   b.setSize(b.getSize() * i);
}

scale메소드를 호출 할 때 IBox인터페이스 를 구현하는 유형의 값을 제공 할 수 있습니다. 즉, if RectangleSquareboth implement IBox이면 a Rectangle또는 Square어디에서든지 IBox기대할 수 있습니다.


8
서브 클래스 및 메소드 재정의를 통해 Java에서 이미 인터페이스 다형성의 목적을 달성 할 수있는 이유는 무엇입니까?
eljenso

1
인터페이스가 구현을 생략해야한다는 점을 제외하고는 동일합니다. 따라서 클래스는 둘 이상의 인터페이스를 구현할 수 있습니다.
Apocalisp

4
이봐, 나는 자바에 어떤 종류의 개념적 무결성이 있다고 말한 적이 없다. 타입 대체는 모든 서브 타이핑의 목적입니다. 자바는 하나 이상의 서브 타이핑 메커니즘을 가지고 있는데, 그중 어느 것도 특별히 좋지는 않다.
Apocalisp

1
나는 개념적 무결성에 대해서도 언급하지 않았습니다. 그러나 계속 갑시다. 메소드로 모든 IBox를 확장 할 수 있다면 IBox에서 선언 된 작업이 아니어야합니다. IBox.scale (int)?
eljenso

1
우리는 Integer를 IBox에 연결하고 싶지 않기 때문에 Integer에서 메소드로 만들지 않습니다. 인터페이스의 메소드 수는 구현하는 것이 번거롭지 않고 표현하는 추상화의 일관성과 응집성에 의해 결정됩니다. 어쨌든, 답변 APO에 감사드립니다.
eljenso

33

인터페이스는 정적으로 입력 된 언어가 다형성을 지원할 수 있도록합니다. 객체 지향적 순수 주의자는 완전한 기능을 갖춘 객체 지향 언어가되기 위해서는 언어가 상속, 캡슐화, 모듈화 및 다형성을 제공해야한다고 주장합니다. 동적 유형 또는 오리 유형 언어 (Smalltalk와 같은)에서 다형성은 사소합니다. 그러나 정적으로 유형이 지정된 언어 (예 : Java 또는 C #)에서 다형성은 사소한 것이 아닙니다 (사실상, 강력한 타이핑 개념과는 상충되는 것 같습니다).

보여 드리겠습니다 :

스몰 토크와 같이 동적으로 유형이 지정된 (또는 오리 유형의) 언어에서 모든 변수는 객체에 대한 참조입니다.

|anAnimal|    
anAnimal := Pig new.
anAnimal makeNoise.

anAnimal := Cow new.
anAnimal makeNoise.

그 코드 :

  1. anAnimal이라는 지역 변수를 선언합니다 (우리는 변수의 TYPE을 지정하지 않습니다. 모든 변수는 더 이상 개체에 대한 참조입니다).
  2. "Pig"라는 클래스의 새 인스턴스를 만듭니다.
  3. 해당 Pig의 새 인스턴스를 변수 anAnimal에 지정합니다.
  4. 메시지를 보냅니다 makeNoise 를 돼지에게 .
  5. 소를 사용하여 모든 것을 반복하지만 돼지와 동일한 정확한 변수에 할당합니다.

동일한 Java 코드는 다음과 같습니다 (Duck과 Cow는 Animal의 하위 클래스라고 가정합니다).

Animal anAnimal = new Pig();
duck.makeNoise();

anAnimal = new Cow();
cow.makeNoise();

우리가 야채 클래스를 소개 할 때까지는 모두 훌륭합니다. 야채는 동물과 같은 행동을하지만 전부는 아닙니다. 예를 들어, 동물과 야채는 모두 자랄 수 있지만 분명히 야채는 소리를 내지 않으며 동물은 수확 할 수 없습니다.

스몰 토크에서는 다음과 같이 쓸 수 있습니다 :

|aFarmObject|
aFarmObject := Cow new.
aFarmObject grow.
aFarmObject makeNoise.

aFarmObject := Corn new.
aFarmObject grow.
aFarmObject harvest.

이것은 오리 유형이기 때문에 Smalltalk에서 완벽하게 작동합니다 (오리처럼 걷고, 오리처럼 qua 경우-오리입니다).이 경우 메시지가 객체로 전송되면 조회가 수행됩니다. 수신자의 메소드 목록 및 일치하는 메소드가 발견되면 호출됩니다. 그렇지 않은 경우 일종의 NoSuchMethodError 예외가 발생하지만 모두 런타임에 완료됩니다.

그러나 정적으로 유형이 지정된 언어 인 Java에서 변수에 어떤 유형을 할당 할 수 있습니까? 옥수수는 채소를 물려 받아 성장을 지원해야하지만 소리를 내지 않기 때문에 동물로부터 물려받을 수는 없습니다. 암소는 makeNoise를 지원하기 위해 동물로부터 물려 받아야하지만, 수확을 구현해서는 안되므로 야채에서는 물려받을 수 없습니다. 다중 상속이 필요한 것 같습니다 . 둘 이상의 클래스에서 상속 할 수 있습니다. 그러나 그것은 팝업이 발생하는 모든 경우 때문에 매우 어려운 언어 기능으로 판명되었습니다 (하나 이상의 병렬 수퍼 클래스가 동일한 메소드를 구현하면 어떻게됩니까? 등).

인터페이스와 함께 ...

Growable을 구현할 때마다 Animal and Vegetable 클래스를 만들면 Cow는 Animal이고 Corn은 Vegetable이라고 선언 할 수 있습니다. 우리는 또한 동물과 야채 모두 성장할 수 있다고 선언 할 수 있습니다. 이를 통해 모든 것을 키울 수 있습니다.

List<Growable> list = new ArrayList<Growable>();
list.add(new Cow());
list.add(new Corn());
list.add(new Pig());

for(Growable g : list) {
   g.grow();
}

동물 소리를 내기 위해 이렇게 할 수 있습니다.

List<Animal> list = new ArrayList<Animal>();
list.add(new Cow());
list.add(new Pig());
for(Animal a : list) {
  a.makeNoise();
}

오리 유형 언어의 장점은 정말 좋은 다형성을 얻는다는 것입니다. 클래스가 행동을 제공하기 위해해야하는 모든 것은 메소드를 제공하는 것입니다. 모두가 훌륭하고 정의 된 메소드와 일치하는 메시지 만 보내는 한 모든 것이 좋습니다. 단점은 런타임까지 아래의 종류의 오류가 포착되지 않는다는 것입니다.

|aFarmObject|
aFarmObject := Corn new.
aFarmObject makeNoise. // No compiler error - not checked until runtime.

정적으로 유형이 지정된 언어는 컴파일 타임에 아래 두 가지 종류의 오류를 포착하기 때문에 "계약에 의한 프로그래밍"이 훨씬 우수합니다.

// Compiler error: Corn cannot be cast to Animal.
Animal farmObject = new Corn();  
farmObject makeNoise();

-

// Compiler error: Animal doesn't have the harvest message.
Animal farmObject = new Cow();
farmObject.harvest(); 

요약하자면 :

  1. 인터페이스 구현을 통해 객체가 수행 할 수있는 작업 유형 (상호 작용)을 지정할 수 있으며 클래스 상속을 통해 작업 수행 방법 (구현)을 지정할 수 있습니다.

  2. 인터페이스는 컴파일러 유형 검사를 희생하지 않고 "진정한"다형성의 많은 이점을 제공합니다.


2
이것은 다른 질문에 대한 내 대답의 텍스트입니다 : stackoverflow.com/questions/379282/… . 그러나 그들은 관련 답변입니다.
Jared

2
오리 형 언어는 어떻게 Animal.water () (농약 한 농민이 새는 것을 말하는데 사용했었다)와 식물에 물을주기 위해 사용하는 Plant.water ()를 어떻게 구별 할 수 있을까요? 모호성은 적입니다. 모호성을 극복하는 데 필요한 모든 정보량은 허용되는 IMO입니다.
Bill K

1
Yep..ambiguity는 오리 형식 언어로 된 게임의 이름입니다. 오리 유형 언어로 전문적으로 작업 할 때 이름이 50-100자인 멤버 (메소드 및 변수)를 보는 것은 드문 일이 아닙니다.
Jared

1
오리 유형 언어의 또 다른 큰 단점은 정적 분석을 기반으로 프로그래밍 방식의 리팩토링을 수행 할 수 없다는 것입니다. printString 메소드의 모든 호출자 목록에 대해 스몰 토크 이미지를 요청하십시오 ... 모든 printString 메소드의 모든 호출자 목록을 얻을 수 있습니다. ...
Jared

... 자동차 #printString의 발신자를 프로그래밍 방식으로 NearEarthOrbit # printString의 발신자와 구별 할 수 없기 때문입니다.
Jared

9

일반적으로 인터페이스는 사용해야하는 인터페이스를 정의합니다 (이름에 ;-)로 표시됨). 견본


public void foo(List l) {
   ... do something
}

이제 함수 foo는 하나의 유형뿐만 아니라 ArrayLists, LinkedLists, ...를 허용 합니다.

Java에서 가장 중요한 것은 여러 인터페이스를 구현할 수 있지만 ONE 클래스 만 확장 할 수 있다는 것입니다! 견본:


class Test extends Foo implements Comparable, Serializable, Formattable {
...
}
가능하지만

class Test extends Foo, Bar, Buz {
...
}
아니다!

위의 코드는 다음과 같습니다 IBox myBox = new Rectangle();.. 중요한 점은 myBox에만 IBox의 메소드 / 필드 만 포함하고의 기존 메소드는 포함하지 않는 것입니다 Rectangle.


1
'List'는 인터페이스 멤버 여야합니까?
Upvote를 클릭하십시오

1
List는 java collections 라이브러리의 인터페이스입니다.
rmeador

List는 표준 Java 라이브러리 ( java.sun.com/javase/6/docs/api/java/util/List.html ) 의 인터페이스입니다 . 그는 단지 그의 요점을 설명하기 위해 그것을 사용하고 있습니다.
Michael Myers

6

인터페이스가하는 모든 것을 이해한다고 생각하지만 인터페이스가 유용한 상황을 아직 상상하지 못하고 있습니다.

좁은 범위 내에서 (예 : 하나의 메서드 호출 내에서) 객체를 인스턴스화, 사용 및 해제하는 경우 인터페이스는 실제로 아무 것도 추가하지 않습니다. 언급했듯이 구체적인 클래스가 알려져 있습니다.

인터페이스가 유용한 곳은 오브젝트를 한 곳에서 작성하고 구현 세부 사항에 관심이없는 호출자에게 리턴해야하는 경우입니다. IBox 예제를 Shape로 변경해 봅시다. 이제 Rectangle, Circle, Triangle 등 Shape의 구현을 가질 수 있습니다. getArea () 및 getSize () 메소드의 구현은 각 구체적인 클래스마다 완전히 다릅니다.

이제 전달 된 매개 변수에 따라 적절한 모양을 반환하는 다양한 createShape (params) 메소드가있는 팩토리를 사용할 수 있습니다. 분명히 팩토리는 어떤 유형의 쉐이프가 생성되는지 알 수 있지만 호출자에게는 없습니다. 원인지 정사각형인지 걱정할 필요가 있습니다.

이제 모양에 대해 다양한 작업을 수행해야한다고 상상해보십시오. 영역별로 정렬하고 새로운 크기로 설정 한 다음 UI에 표시해야 할 수도 있습니다. 셰이프는 모두 팩토리에서 만든 다음 Sorter, Sizer 및 Display 클래스로 매우 쉽게 전달 될 수 있습니다. 나중에 육각 클래스를 추가해야 할 경우 팩토리 이외의 것을 변경할 필요가 없습니다. 인터페이스가 없으면 다른 모양을 추가하는 것은 매우 복잡한 과정이됩니다.


6

넌 할 수있어

Ibox myBox = new Rectangle();

그렇게하면이 객체를 Ibox로 사용하고 실제로 신경 쓰지 않습니다 Rectangle.


그것은 우리가 이렇게 쓸 수 있다는 것을 의미합니까?! > 사각형 inst = 새 사각형 ();
Dr.jacky

@ Mr.Hyde 나중에 추가 할 경우 Square당신이 인터페이스없이 수행하려고 할 경우 .... 문제가있는 것, 당신이 할 수없는 보장 Square하고 Rectangle당신이있을 때 같은 방법이 ...이 악몽이 발생할 수 있습니다 더 큰 코드 기반 ... 인터페이스가 템플릿을 정의한다는 것을 기억하십시오.
Kolob Canyon

6

왜 인터페이스인가 ??????

개로 시작합니다. 특히, 퍼그 .

퍼그에는 다양한 동작이 있습니다.

public class Pug { 
private String name;
public Pug(String n) { name = n; } 
public String getName() { return name; }  
public String bark() { return  "Arf!"; } 
public boolean hasCurlyTail() { return true; } }

그리고 당신은 래브라도를 가지고 있습니다.

public class Lab { 
private String name; 
public Lab(String n) { name = n; } 
public String getName() { return name; } 
public String bark() { return "Woof!"; } 
public boolean hasCurlyTail() { return false; } }

퍼그와 랩을 만들 수 있습니다 :

Pug pug = new Pug("Spot"); 
Lab lab = new Lab("Fido");

그리고 우리는 그들의 행동을 불러 낼 수 있습니다 :

pug.bark() -> "Arf!" 
lab.bark() -> "Woof!" 
pug.hasCurlyTail() -> true 
lab.hasCurlyTail() -> false 
pug.getName() -> "Spot"

개 사육장을 운영하고 있으며 내가 살고있는 모든 개를 추적해야한다고 가정 해 봅시다. 나는 별도의 배열에 내 퍼그와 래브라도을 저장해야합니다 :

public class Kennel { 
Pug[] pugs = new Pug[10]; 
Lab[] labs = new Lab[10];  
public void addPug(Pug p) { ... } 
public void addLab(Lab l) { ... } 
public void printDogs() { // Display names of all the dogs } }

그러나 이것은 분명히 최적이 아닙니다. 경우 좀 푸들을 수용 할 도, 나는 푸들의 배열을 추가 내 개집 정의를 변경해야합니다. 사실, 나는 개 종류마다 별도의 배열이 필요합니다.

통찰력 : 퍼그와 래브라도 (푸들)는 개 유형이며 같은 행동을 취합니다. 즉, 우리는 (이 예의 목적을 위해) 모든 개가 짖을 수 있고 이름을 가질 수 있으며 곱슬 꼬리를 가질 수도 있고 말지 않을 수도 있다고 말할 수 있습니다. 인터페이스를 사용하여 모든 개가 할 수있는 일을 정의 할 수 있지만 특정 행동 유형을 구현하기 위해 특정 유형의 개에 맡겨 두십시오. 인터페이스는 "모든 개가 할 수있는 일이 있습니다"라고 말하지만 각 행동이 어떻게 수행되는지는 말하지 않습니다.

public interface Dog 
{
public String bark(); 
public String getName(); 
public boolean hasCurlyTail(); }

그런 다음 Pug 및 Lab 클래스를 약간 변경하여 Dog 동작을 구현합니다. 퍼그는 개이고 랩은 개라고 말할 수 있습니다.

public class Pug implements Dog {
// the rest is the same as before } 

public class Lab implements Dog { 
// the rest is the same as before 
}

이전과 마찬가지로 여전히 퍼그와 랩을 인스턴스화 할 수 있지만 이제는 새로운 방법을 사용할 수 있습니다.

Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido");

이것은 d1은 개일뿐만 아니라, 특히 퍼그입니다. d2는 또한 개, 특히 실험실입니다. 동작을 호출 할 수 있으며 이전과 같이 작동합니다.

d1.bark() -> "Arf!" 
d2.bark() -> "Woof!" 
d1.hasCurlyTail() -> true 
d2.hasCurlyTail() -> false 
d1.getName() -> "Spot"

추가 작업이 모두 필요한 곳입니다. Kennel 클래스가 훨씬 단순 해졌습니다. 하나의 배열과 하나의 addDog 메소드 만 필요합니다. 둘 다 개인 어떤 물건과도 잘 어울립니다. 즉, Dog 인터페이스를 구현하는 객체입니다.

public class Kennel {
Dog[] dogs = new Dog[20]; 
public void addDog(Dog d) { ... } 
public void printDogs() {
// Display names of all the dogs } }

사용 방법은 다음과 같습니다.

Kennel k = new Kennel(); 
Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido"); 
k.addDog(d1); 
k.addDog(d2); 
k.printDogs();

마지막 문장은 스팟 피도

인터페이스는 인터페이스를 구현하는 모든 클래스가 공통으로 공유 할 일련의 동작을 지정할 수있는 기능을 제공합니다. 결과적으로, 어떤 종류의 특정 객체를 미리 알 필요가없고 인터페이스를 구현하는 객체 만 보유 할 변수와 컬렉션 (예 : 배열)을 정의 할 수 있습니다.


@ niranjan kurambhatti 나는 개를 확장하기 위해 모든 클래스를 만들 수 있지만 여전히 인터페이스는 무엇입니까 ??
Jeeva

3

인터페이스 사용 방법의 훌륭한 예는 Collections 프레임 워크에 있습니다. 를 사용하는 함수를 작성 List하면 사용자가 a Vector또는 an ArrayList또는 a HashList또는 무엇이든 전달하는지는 중요하지 않습니다 . 또한 인터페이스 또는 인터페이스가 List필요한 모든 기능으로 전달할 수 있습니다.CollectionIterable

이것은 구현 Collections.sort(List list)방법에 관계없이 기능을 가능 하게합니다 List.


3

이것이 팩토리 패턴 및 기타 작성 패턴이 Java에서 그렇게 인기있는 이유 입니다. Java가 없으면 인스턴스화를 쉽게 추상화 할 수있는 즉시 사용 가능한 메커니즘을 제공하지 않습니다. 여전히 메서드에서 객체를 만들지 않는 모든 곳에서 추상화를 얻습니다 .이 코드는 대부분의 코드입니다.

따로, 나는 일반적으로 사람들에게 인터페이스 이름 지정을위한 "IRealname"메커니즘을 따르지 말 것을 권장합니다. 그것은 헝가리어 표기법의 한 발자국에 발을 들여 놓고 실제로 필요하지 않은 Windows / COM 일입니다 (Java는 이미 강력하게 유형이 지정되어 있으며 인터페이스를 갖는 요점은 가능한 한 클래스 유형과 구별 할 수 없도록하는 것입니다).


1
강력한 타이핑과 정적 타이핑을 혼동하고 있습니다.
eljenso

3

나중에 기존 클래스를 가져 와서 구현 IBox하면 모든 상자 인식 코드에서 사용할 수 있음을 잊지 마십시오 .

인터페이스의 이름이 -able 인 경우 좀 더 명확 해집니다 . 예 :

public interface Saveable {
....

public interface Printable {
....

등. (이름 지정 체계가 항상 작동하는 것은 아닙니다. 예를 들어 Boxable여기가 적절 하지는 않습니다 )


3

인터페이스의 유일한 목적은 인터페이스를 구현하는 클래스가 인터페이스에 설명 된대로 올바른 메소드를 가지고 있는지 확인하는 것입니다. 아니면 다른 인터페이스 사용이 있습니까?

Java 8 버전으로 도입 된 새로운 인터페이스 기능으로 답변을 업데이트하고 있습니다.

인터페이스 요약대한 오라클 설명서 페이지에서 :

인터페이스 선언은

  1. 메소드 서명
  2. 기본 방법
  3. 정적 메소드
  4. 상수 정의.

구현이있는 유일한 메소드는 기본 및 정적 메소드입니다.

인터페이스 사용 :

  1. 계약 을 정의하려면
  2. 관련이없는 클래스 를 기능과 연결 하는 것 (예 : Serializable인터페이스를 구현하는 클래스 는 해당 인터페이스를 구현하는 것 외에는 관계가있을 수도 있고 없을 수도 있음)
  3. 교환 가능한 구현 을 제공하기 위해 전략 패턴
  4. 기본 방법을 사용하면 라이브러리의 인터페이스에 새로운 기능을 추가하고 해당 인터페이스의 이전 버전 용으로 작성된 코드와 이진 호환성을 보장 할 수 있습니다
  5. 정적 메소드 를 사용하여 라이브러리에서 헬퍼 메소드 구성 (정적 메소드는 별도의 클래스가 아닌 동일한 인터페이스에서 인터페이스에 고유 한 정적 메소드를 유지할 수 있음)

실습 예제와 함께 추상 클래스인터페이스 및 사용 사례의 차이점과 관련된 몇 가지 관련 SE 질문 :

인터페이스와 추상 클래스의 차이점은 무엇입니까?

Interface와 Abstract 클래스의 차이점을 어떻게 설명해야합니까?

한 번 봐 가지고 문서 : 자바 8에 추가 된 새로운 기능을 이해하는 페이지 기본 방법과 정적 메서드를 .


질문 이 java-8에 대해 아무것도 묻지 않았기 때문에 java-8 태그를 제거했습니다 (실제로 java-8보다 오래 전에 요청되었습니다). 태그는 질문이 아닌 답변입니다.
Tagir Valeev 2016 년

2

인터페이스의 목적은 추상화 또는 구현과의 분리입니다.

프로그램에 추상화를 도입하면 가능한 구현에 신경 쓰지 않습니다. 에 관심이 무엇인지 는 할 수없는 방법 , 당신은 사용 interface자바에서 이것을 표현.


모든 구조화 된 프로그래밍의 목적은 추상화입니다. 제네릭과 클래스 구성을 사용하여 똑같은 것을 얻을 수 있기 때문에 인터페이스의 목적이 추상화라고 생각하는 이유는 무엇입니까?
Apocalisp

1
모든 구조화 된 프로그래밍이 추상화 (귀하의 주장) 인 경우 인터페이스는 해당 추상화의 추상화입니다.
eljenso

1

CardboardBox 및 HtmlBox (둘 다 IBox를 구현)가있는 경우 둘 다 IBox를 허용하는 모든 메서드에 전달할 수 있습니다. 그것들이 매우 다르고 완전히 상호 교환 할 수는 없지만 "열기"나 "크기 조정"에 신경 쓰지 않는 메소드는 여전히 클래스를 사용할 수 있습니다 (아마도 화면에 무언가를 표시하는 데 필요한 픽셀 수에 관심이 있기 때문에).


1

다중 상속을 허용하기 위해 fetature가 java에 추가 된 인터페이스. Java 개발자는 다중 상속을 갖는 것이 "위험한"기능이라는 사실을 깨달았습니다. 이것이 인터페이스라는 아이디어를 내놓은 이유입니다.

다중 상속은 다음과 같은 클래스를 가질 수 있으므로 위험합니다.


class Box{
    public int getSize(){
       return 0;
    }
    public int getArea(){
       return 1;
    }

}

class Triangle{
    public int getSize(){
       return 1;
    }
    public int getArea(){
       return 0;
    }

}

class FunckyFigure extends Box, Triable{
   // we do not implement the methods we will used the inherited ones
}

우리가 사용할 때 호출 해야하는 방법은 무엇입니까


   FunckyFigure.GetArea(); 

인터페이스를 확장 할 수 있고 클래스 화 메소드가 없다는 것을 알고 있기 때문에 모든 문제가 인터페이스로 해결됩니다 ... 물론 컴파일러는 훌륭하고 메소드를 구현하지 않은 경우 알려줍니다. 더 흥미로운 아이디어의 부작용.


답변에서 여러 구현 상속과 여러 인터페이스 상속을 다르게 할 수 있습니다. 그렇지 않으면 혼란스러워집니다.
eljenso

0

다음은 인터페이스 이점에 대한 이해입니다. 내가 틀렸다면 나를 바로 잡으십시오. 우리가 OS를 개발하고 있고 다른 팀이 일부 장치의 드라이버를 개발하고 있다고 상상해보십시오. 그래서 우리는 인터페이스 StorageDevice를 개발했습니다. 다른 개발자 팀에서 제공 한 두 가지 구현 (FDD 및 HDD)이 있습니다.

그런 다음 StorageDevice 인터페이스를 구현 한 클래스의 인스턴스를 전달하여 saveData와 같은 인터페이스 메소드를 호출 할 수있는 OperatingSystem 클래스가 있습니다.

여기서 장점은 인터페이스 구현에 신경 쓰지 않는다는 것입니다. 다른 팀은 StorageDevice 인터페이스를 구현하여 작업을 수행합니다.

package mypack;

interface StorageDevice {
    void saveData (String data);
}


class FDD implements StorageDevice {
    public void saveData (String data) {
        System.out.println("Save to floppy drive! Data: "+data);
    }
}

class HDD implements StorageDevice {
    public void saveData (String data) {
        System.out.println("Save to hard disk drive! Data: "+data);
    }
}

class OperatingSystem {
    public String name;
    StorageDevice[] devices;
    public OperatingSystem(String name, StorageDevice[] devices) {

        this.name = name;
        this.devices = devices.clone();

        System.out.println("Running OS " + this.name);
        System.out.println("List with storage devices available:");
        for (StorageDevice s: devices) {
            System.out.println(s);
        }

    }

    public void saveSomeDataToStorageDevice (StorageDevice storage, String data) {
        storage.saveData(data);
    }
}

public class Main {

    public static void main(String[] args) {

        StorageDevice fdd0 = new FDD();
        StorageDevice hdd0 = new HDD();     
        StorageDevice[] devs = {fdd0, hdd0};        
        OperatingSystem os = new OperatingSystem("Linux", devs);
        os.saveSomeDataToStorageDevice(fdd0, "blah, blah, blah...");    
    }
}

추상 클래스 StorageDevice 및 StorageDevice 클래스를 확장하는 FDD 및 HDD 클래스를 사용하여 동일한 작업을 수행 할 수 있습니다. 그러나 추상 클래스를 사용하면 다중 상속을 이용할 수 없습니다.
Vladimir Georgiev
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.