인터페이스를 구현하는 추상 클래스가 인터페이스 메서드 중 하나의 선언 / 구현을 놓칠 수있는 이유는 무엇입니까?


123

인터페이스를 구현하기 위해 추상 클래스를 사용할 때 Java에서 흥미로운 일이 발생합니다. 인터페이스의 메서드 중 일부가 완전히 누락 될 수 있지만 (즉, 추상 선언이나 실제 구현이 존재하지 않음) 컴파일러가 불평하지 않습니다.

예를 들어 다음과 같은 인터페이스가 있습니다.

public interface IAnything {
  void m1();
  void m2();
  void m3();
}

다음 추상 클래스는 경고 나 오류없이 즐겁게 컴파일됩니다.

public abstract class AbstractThing implements IAnything {
  public void m1() {}
  public void m3() {}
}

이유를 설명해 주시겠습니까?


2
추상 클래스의 객체를 만들 수 없습니다. 따라서 추상 클래스에 대한 구현이 제공되지 않는 한 IAnything에 대한 개체를 만들 수 없습니다. 따라서 이것은 컴파일러에게는 절대적으로 좋습니다. 컴파일러는 IAnything을 구현하는 비추 상 클래스는 IAnything에서 선언 된 모든 메서드를 구현해야한다고 예상합니다. 그리고 객체를 생성하려면 AbstractThing을 확장하고 구현해야하므로 해당 구현이 AbstractThing에서 제외 된 IAnything의 메서드를 구현하지 않으면 컴파일러에서 오류가 발생합니다.
VanagaS

나는 이것과 동일한 시나리오에서 자체 "AbstractThing"을 확장하는 구체적인 클래스를 가지고 있었고, 인터페이스에서 메소드 중 하나를 구현하지 않았음에도 불구하고 설명 할 수 없을 정도로 컴파일되었습니다. 이제는 내가 기대 한대로하고 있지만 이전에 성공한 원인을 파악할 수 없습니다. :w파일 중 하나 가 아닌 것 같습니다 .
Braden Best

비슷한 질문에 대한 답변을 볼 수 있습니다. stackoverflow.com/questions/8026580/…
Do Nhu Vy

답변:


156

클래스가 추상적 인 경우 정의에 따라 인스턴스화 할 하위 클래스를 만들어야하기 때문입니다. 하위 클래스는 추상 클래스가 생략 한 인터페이스 메서드를 구현하기 위해 컴파일러에 의해 필요합니다.

예제 코드에 AbstractThing따라 m2메서드 를 구현하지 않고 의 하위 클래스를 만들고 컴파일러가 제공하는 오류를 확인하십시오. 이 방법을 구현해야합니다.


1
나는 컴파일러가 인터페이스를 불완전하게 구현하는 추상 클래스에 대한 경고를 던져야한다고 생각한다. 그 이유는 단순히 서브 클래스에서 필요한 것을보기 위해 1 개가 아닌 2 개의 클래스 정의를 살펴 봐야하기 때문이다. 이것은 언어 / 컴파일러 제한입니다.
workmad3

3
일반적으로 많은 추상 클래스가있을 수 있고 '거짓'경고가 곧 당신을 압도하여 '진짜'경고를 놓칠 수 있기 때문에 좋은 생각이 아닙니다. 생각해 보면 'abstract'키워드는 특별히 컴파일러에게 해당 클래스에 대한 경고를 억제하도록 지시하는 것입니다.
belugabob

4
@workmad-인터페이스 메서드의 하위 집합에 대한 공통 구현이있는 경우이를 별도의 기본 클래스로 고려하는 것이 더 좋습니다 (DRY가 한 자리 코드보다 우선 함)
Gishu

4
추상 클래스에 빈 메서드 구현을 넣 도록 요구하는 것은 위험합니다 . 그렇게하면 하위 클래스의 구현자는 컴파일러가 문제가 있음을 알리지 않고이 비 동작을 상속 할 것입니다.
Bill the Lizard

8
workmad가 제안 할 수있는 것은 메서드 본문없이 추상 클래스에서 메서드를 정의하고 추상으로 표시하는 것입니다. 나에게 나쁜 생각처럼 보이지 않습니다.
Dónal

33

완벽합니다.
추상 클래스를 인스턴스화 할 수는 없지만 추상 클래스를 사용하여 m1 () 및 m3 ()에 대한 공통 구현을 수용 할 수 있습니다.
그래서 만약 m2 () 구현은 각 구현 다르지만 M1 및 m3는 없다. 다른 m2 구현만으로 다른 구체적인 IAnything 구현을 만들고 AbstractThing에서 파생하여 DRY 원칙을 준수 할 수 있습니다. 인터페이스가 추상 클래스에 대해 완전히 구현되었는지 확인하는 것은 헛된 일입니다.

업데이트 : 흥미롭게도 C #이 이것을 컴파일 오류로 강제한다는 것을 알았습니다. 이 시나리오의 추상 기본 클래스에서 메서드 서명을 복사하고 'abstract public'접두사를 붙여야합니다. (매일 새로운 것 :)


7

괜찮아. 위의 내용을 이해하려면 먼저 추상 클래스의 특성을 이해해야합니다. 그 점에서 인터페이스와 유사합니다. 이것이 오라클이 여기에서 말하는 입니다.

추상 클래스는 인터페이스와 유사합니다. 인스턴스화 할 수 없으며 구현 여부에 관계없이 선언 된 메서드 혼합이 포함될 수 있습니다.

따라서 인터페이스가 다른 인터페이스를 확장 할 때 어떤 일이 발생하는지 생각해야합니다. 예를 들어 ...

//Filename: Sports.java
public interface Sports
{
   public void setHomeTeam(String name);
   public void setVisitingTeam(String name);
}

//Filename: Football.java
public interface Football extends Sports
{
   public void homeTeamScored(int points);
   public void visitingTeamScored(int points);
   public void endOfQuarter(int quarter);
}

... 보시다시피, 이것도 완벽하게 잘 컴파일됩니다. 단순히 추상 클래스와 마찬가지로 인터페이스를 인스턴스화 할 수 없기 때문입니다. 따라서 "부모"에서 메서드를 명시 적으로 언급 할 필요가 없습니다. 그러나 모든 부모 메서드 서명은 암시 적으로 확장 인터페이스의 일부가되거나 추상 클래스를 구현합니다. 따라서 적절한 클래스 (인스턴스화 할 수있는 클래스)가 위를 확장하면 모든 단일 추상 메서드가 구현되었는지 확인해야합니다.

도움이되는 희망 ... 그리고 Allahu 'alam!


그것은 흥미로운 관점입니다. 이것은 "추상 클래스"가 실제로 "구체적인 인터페이스"라고 생각하게합니다. 즉, 추상 메서드가있는 클래스가 아니라 구체적인 메서드가있는 인터페이스입니다.
Giulio Piancastelli

... 둘 다 정말. 그러나 확실히 한 가지는 인스턴스화 할 수 없다는 것입니다.
감사합니다

4

인터페이스는 메소드 구현이 없지만 선언 만있는 클래스를 의미합니다.
한편, 추상 클래스는 구현없이 선언 만있는 일부 메서드와 함께 일부 메서드를 구현할 수있는 클래스입니다.
추상 클래스에 대한 인터페이스를 구현하면 추상 클래스가 인터페이스의 모든 메서드를 상속했음을 의미합니다. 따라서 추상 클래스에서 모든 메서드를 구현하는 것은 중요하지 않지만 추상 클래스 (상속에 의해)가되므로 추상 클래스는 여기에서 구현하지 않고 인터페이스에 일부 메서드를 남길 수 있습니다. 그러나이 추상 클래스가 특정 클래스에 의해 상속 될 때 구현되지 않은 모든 메서드를 추상 클래스에 구현해야합니다.


4

주어진 인터페이스 :

public interface IAnything {
  int i;
  void m1();
  void m2();
  void m3();
}

이것이 Java가 실제로 보는 방식입니다.

public interface IAnything {
  public static final int i;
  public abstract void m1();
  public abstract void m2();
  public abstract void m3();
}

따라서 다른 클래스를 확장 abstract하는 abstract클래스 의 경우처럼 이러한 메서드 중 일부 (또는 전체)를 구현하지 않은 채로 둘 수 있습니다.abstract 클래스를 .

때 , 모든 것을 규칙 방법이 파생에서 구현해야이 만 콘크리트에 적용 되지 않습니다 구현 (즉,implementinterfaceinterfaceclassclassabstract 자체).

당신은 참으로 만들 계획이라면 abstract class그것을 밖으로을, 다음에했습니다 말한다 아무런 규칙이없는 implement모든 interface(이러한 경우에 파생 선언하는 필수주의 방법 class으로는 abstract)


javap IAnything.class두 번째 코드 조각을 생성하는 데 사용 합니다.
sharhp

3

추상 클래스가 인터페이스를 구현할 때

인터페이스 섹션에서 인터페이스를 구현하는 클래스는 인터페이스의 모든 메소드를 구현해야한다는 점을 언급했습니다. 그러나 클래스가 추상으로 선언 된 경우 인터페이스의 모든 메서드를 구현하지 않는 클래스를 정의 할 수 있습니다. 예를 들면

abstract class X implements Y {   
    // implements all but one method of Y
}

class XX extends X {   
    // implements the remaining method in Y 
} 

이 경우 클래스 X는 Y를 완전히 구현하지 않기 때문에 추상이어야하지만 실제로 클래스 XX는 Y를 구현합니다.

참조 : http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html


1

메서드를 구현하는 데 추상 클래스가 필요하지 않습니다. 따라서 인터페이스를 구현하더라도 인터페이스의 추상 메서드는 추상을 유지할 수 있습니다. 추상이 아닌 구체적인 클래스에서 인터페이스를 구현하려고하고 추상 메서드를 구현하지 않으면 컴파일러는 다음과 같이 알려줍니다. 추상 메서드를 구현하거나 클래스를 추상으로 선언합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.