2008-10-13 3 views
99

추상 클래스를 사용하여 인터페이스를 구현할 때 자바에서 이상한 일이 발생합니다. 일부 인터페이스 메소드가 완전히 누락 될 수 있습니다 (즉, 추상 선언이나 실제 구현이 없음).하지만 컴파일러는 불평하지 않습니다.인터페이스를 구현하는 추상 클래스가 인터페이스 메소드 중 하나의 선언/구현을 놓칠 수있는 이유는 무엇입니까?

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

다음 추상 클래스가 명랑하게 경고 또는 오류없이 컴파일됩니다 :

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

당신이 이유를 설명 할 수있는 인터페이스를 제공 예를 들어

?

+0

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

+0

"어댑터 설계 패턴"이라고 부를 수 있습니까? 우리가 m1, m2, m3을 추상 클래스에서 빈 몸체로 유지한다면. 그런 다음 MyMainClass는 해당 추상 클래스를 확장하고 원하는 모든 메서드를 재정의 할 수 있습니다. 모든 메서드를 재정의 할 필요는 없습니다. 알려주세요 !! –

답변

130

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

예제 코드에 따라 m2 메서드를 구현하지 않고 AbstractThing의 하위 클래스를 만들고 컴파일러에서 제공하는 오류를 확인하십시오. 이 메소드를 구현하도록 강요합니다.

+0

나는 컴파일러가 여전히 불완전하게 인터페이스를 구현하는 추상 클래스에 관한 경고를 던져야한다고 생각한다. 왜냐하면 단순히 서브 클래스에서 무엇이 필요한지를보기 위해 1보다는 2 개의 클래스 정의를 조사해야하기 때문이다. 이것은 언어/컴파일러 제한이다. – workmad3

+3

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

+4

@workmad - 인터페이스 메소드의 서브 세트에 공통적 인 구현이있는 경우 별도의 기본 클래스로 인수를 지정하는 것이 좋습니다 (DRY가 1 자리 코드보다 우선 함) – Gishu

30

완벽하게 좋습니다.
추상 클래스를 인스턴스화 할 수는 없지만 추상 클래스는 m1() 및 m3()에 대한 일반적인 구현을 수용하는 데 사용할 수 있습니다.
m2() 구현은 구현마다 다르지만 m1 및 m3은 그렇지 않습니다. 서로 다른 m2 구현을 사용하여 서로 다른 구체적인 IAnything 구현을 만들고 AbstractThing에서 파생됩니다. DRY 원칙을 존중합니다. 인터페이스가 추상 클래스에 대해 완전히 구현 된 경우 유효성 검사는 무의미합니다 ..

업데이트 : 흥미롭게도 C#은 컴파일 오류로 이것을 시행합니다. 당신은 메소드 시그니처를 복사하고이 시나리오의 추상 기본 클래스에 'abstract public'이라는 접두어를 붙이도록 강요받습니다. (매일 새로운 뭔가가 있습니다 :

1

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

2

인터페이스는 메서드 구현이 없지만 선언 만있는 클래스를 의미합니다.
다른 한편, 추상 클래스는 선언과 구현이없는 일부 메소드와 함께 일부 메소드의 구현을 가질 수있는 클래스입니다.
추상 클래스에 대한 인터페이스를 구현할 때, 추상 클래스는 인터페이스의 모든 메소드를 상속 받았다는 것을 의미합니다. 마찬가지로 추상 클래스에서 모든 메소드를 구현하는 것은 중요하지 않지만 추상 클래스는 (상속을 통해) 제공되므로 추상 클래스는 구현하지 않고 인터페이스의 일부 메소드를 그대로 남겨 둘 수 있습니다. 그러나이 추상 클래스가 특정 클래스에 상속 될 때는 추상 클래스에 구현되지 않은 모든 메소드를 구현해야합니다.

5

괜찮습니다. 위의 내용을 이해하려면 먼저 추상 클래스의 특성을 이해해야합니다. 그것들은 그 점에서 인터페이스와 비슷합니다. 이것이 오라클이 말하는이 here입니다.

Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation.

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

//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); 
} 

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

호프가 도움이 되길 ... 그리고 알라후 'alam!

+0

그것은 재미있는 관점입니다. "추상적 클래스"는 실제로 "구체적인 인터페이스", 즉 몇 가지 추상적 인 메서드가있는 클래스가 아닌 몇 가지 구체적인 메서드가있는 인터페이스라고 생각하게 만듭니다. –

+0

... 둘다 조금 있습니다. 하지만 확실히 한 가지, 그들은 구체화되지 않습니다. – Grateful

2

When an Abstract Class Implements an Interface

In the section on Interfaces, it was noted that a class that implements an interface must implement all of the interface's methods. It is possible, however, to define a class that does not implement all of the interface's methods, provided that the class is declared to be abstract. For example,

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

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

In this case, class X must be abstract because it does not fully implement Y, but class XX does, in fact, implement Y.

참조 : 인터페이스 주어 http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

1

는 :

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

이 호입니다 자바는 실제로 그것을보고 W :

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

그래서 당신은 당신이 다른 abstract 클래스를 확장 abstract 클래스의 경우에서하는 것처럼,이 abstract 방법 중 일부 (또는 전부)가 구현되어 있지 않은 남길 수 있습니다.

하면 interfaceimplement는 모든 interface 방법 도출 class에서 구현되어야하는 규칙 (abstract 자체가 아닌, 즉,) 콘크리트 class 구현에만 적용

.

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

+0

'javap IAnything.class'를 사용하여 두 번째 코드 스 니펫을 생성합니다. – sharhp

관련 문제