동일한 메소드를 사용하여 클래스에 두 개의 인터페이스를 구현합니다. 어떤 인터페이스 방법이 재정의됩니까?
메소드 이름과 서명이 동일한 두 개의 인터페이스. 그러나 단일 클래스로 구현하면 컴파일러가 어떤 인터페이스가 어떤 인터페이스인지 식별하는 방법은 무엇입니까?
전의:
interface A{
int f();
}
interface B{
int f();
}
class Test implements A, B{
public static void main(String... args) throws Exception{
}
@Override
public int f() { // from which interface A or B
return 0;
}
}
유형이 두 개의 인터페이스를 구현하고 각각 interface
동일한 서명을 가진 메소드를 정의하는 경우 실제로는 하나의 메소드 만 있으며 구별 할 수 없습니다. 예를 들어 두 메소드가 리턴 유형이 충돌하면 컴파일 오류가됩니다. 이것은 상속, 메소드 재정의, 숨기기 및 선언의 일반적인 규칙이며, 상속 된 두 interface
메소드뿐만 아니라 interface
슈퍼 class
메소드 사이의 가능한 충돌에도 적용 되거나 제네릭의 유형 삭제로 인한 충돌에도 적용됩니다.
호환성 예
여기에 당신이이 예입니다 interface Gift
이있는, present()
그리고 또한, (제시 선물에서와 같이) 방법을 interface Guest
또한 가지고있는, present()
(, 게스트가없는 현재와하지에로) 방법을.
Presentable johnny
a Gift
와 a Guest
입니다.
public class InterfaceTest {
interface Gift { void present(); }
interface Guest { void present(); }
interface Presentable extends Gift, Guest { }
public static void main(String[] args) {
Presentable johnny = new Presentable() {
@Override public void present() {
System.out.println("Heeeereee's Johnny!!!");
}
};
johnny.present(); // "Heeeereee's Johnny!!!"
((Gift) johnny).present(); // "Heeeereee's Johnny!!!"
((Guest) johnny).present(); // "Heeeereee's Johnny!!!"
Gift johnnyAsGift = (Gift) johnny;
johnnyAsGift.present(); // "Heeeereee's Johnny!!!"
Guest johnnyAsGuest = (Guest) johnny;
johnnyAsGuest.present(); // "Heeeereee's Johnny!!!"
}
}
위의 스 니펫은 컴파일되고 실행됩니다.
참고 하나가 @Override
필요합니다! . 이 때문입니다 Gift.present()
및 Guest.present()
"이다 @Override
(-equivalent" JLS 8.4.2 ).
따라서의 johnny
구현 은 하나만 있으며 a로 또는 a 로 present()
처리하는 방법은 중요하지 않습니다 . 호출 할 메소드는 하나뿐입니다.johnny
Gift
Guest
비 호환성 예
다음은 상속 된 두 메소드가 동일하지 않은 예입니다 @Override
.
public class InterfaceTest {
interface Gift { void present(); }
interface Guest { boolean present(); }
interface Presentable extends Gift, Guest { } // DOES NOT COMPILE!!!
// "types InterfaceTest.Guest and InterfaceTest.Gift are incompatible;
// both define present(), but with unrelated return types"
}
이것은 또한 멤버로부터 상속받는 멤버 interface
가 멤버 선언의 일반적인 규칙을 준수해야 함을 반복합니다 . 여기에서 우리는이 Gift
와 Guest
정의 present()
호환되지 않는 반환 형식으로 하나 void
다른 boolean
. 같은 이유로 당신은 할 수 없다는 void present()
하고 boolean present()
한 가지 유형에서, 컴파일 오류이 예의 결과.
요약
@Override
메서드 재정의 및 숨기기의 일반적인 요구 사항에 따라 동등한 메서드를 상속 할 수 있습니다 . 그들은 이후 내용입니다 @Override
-equivalent 효과적으로 구현하는 하나의 방법이있다, 따라서 선택 / 구별 할 것도 없다.
컴파일러는 어떤 인터페이스가 어떤 인터페이스에 적합한 지 식별 할 필요가 없습니다. 일단 @Override
동등한 것으로 판단 되면 동일한 메소드 이기 때문 입니다.
잠재적 인 비 호환성 문제를 해결하는 것은 까다로운 작업 일 수 있지만 이는 또 다른 문제입니다.
참고 문헌
- JLS 8.4.2 메소드 서명
- JLS 8.4.8 상속, 재정의 및 숨기기
- JLS 8.4.8.3 재정의 및 숨기기 요구 사항
- JLS 8.4.8.4 재정의와 동등한 서명을 가진 상속 방법
- "클래스가 재정의와 동등한 서명으로 여러 메소드를 상속 할 수 있습니다."
이것은이 질문에 중복으로 표시되었습니다 https://stackoverflow.com/questions/24401064/understanding-and-solving-the-diamond-problems-in-java
다중 상속 문제를 얻으려면 Java 8이 필요하지만 여전히 그러한 문제는 아닙니다.
interface A {
default void hi() { System.out.println("A"); }
}
interface B {
default void hi() { System.out.println("B"); }
}
class AB implements A, B { // won't compile
}
new AB().hi(); // won't compile.
JB Nizet가 언급 한 것처럼이 문제를 해결할 수 있습니다.
class AB implements A, B {
public void hi() { A.super.hi(); }
}
그러나, 당신은 문제가 없습니다
interface D extends A { }
interface E extends A { }
interface F extends A {
default void hi() { System.out.println("F"); }
}
class DE implement D, E { }
new DE().hi(); // prints A
class DEF implement D, E, F { }
new DEF().hi(); // prints F as it is closer in the heirarchy than A.
컴파일러에 관한 한이 두 방법은 동일합니다. 두 가지 모두 한 가지 구현이 있습니다.
두 메소드가 동일한 구현을 가져야한다는 점에서 두 메소드가 효과적으로 동일한 경우에는 문제가되지 않습니다. 계약이 다르면 (각 인터페이스의 설명서에 따라) 문제가 발생합니다.
식별 할 것이 없습니다. 인터페이스는 메소드 이름과 서명 만 제공합니다. 두 인터페이스 모두 정확히 동일한 이름과 서명의 메소드를 갖는 경우 구현 클래스는 하나의 구체적인 메소드로 두 인터페이스 메소드를 모두 구현할 수 있습니다.
그러나 두 인터페이스 방법 의 의미 적 계약이 모순되는 경우 거의 손실 된 것입니다. 그러면 단일 클래스에서 두 인터페이스를 모두 구현할 수 없습니다.
익명으로 인터페이스를 구현하십시오.
public class MyClass extends MySuperClass implements MyInterface{
MyInterface myInterface = new MyInterface(){
/* Overrided method from interface */
@override
public void method1(){
}
};
/* Overrided method from superclass*/
@override
public void method1(){
}
}
인터페이스에서와 같이 우리는 단지 메소드를 선언하고 있습니다.이 두 인터페이스를 모두 구현하는 콘크리트 클래스는 하나의 메소드 만 있다는 것을 이해합니다 (둘 다 리턴 유형에서 동일한 이름을 가짐). 문제가 없어야합니다. 구체적인 클래스에서 해당 메소드를 정의 할 수 있습니다.
그러나 두 인터페이스가 이름은 같지만 리턴 유형이 다른 메소드를 가지고 있고 구체적인 클래스에서 두 가지 메소드를 구현 한 경우 :
아래 코드를보십시오 :
public interface InterfaceA {
public void print();
}
public interface InterfaceB {
public int print();
}
public class ClassAB implements InterfaceA, InterfaceB {
public void print()
{
System.out.println("Inside InterfaceA");
}
public int print()
{
System.out.println("Inside InterfaceB");
return 5;
}
}
컴파일러가 "public void print ()"메서드를 가져 오면 먼저 InterfaceA를 살펴보고 가져옵니다. 그러나 여전히 반환 형식이 InterfaceB의 메서드와 호환되지 않는 컴파일 시간 오류가 발생합니다.
그래서 컴파일러를 위해 haywire로갑니다.
이런 방식으로 이름은 같지만 리턴 유형이 다른 메소드를 갖는 두 개의 인터페이스를 구현할 수 없습니다.
둘 다 같으면 문제가되지 않습니다. 인터페이스 방법마다 하나의 구체적인 방법으로 두 가지를 모두 구현합니다.
'Programing' 카테고리의 다른 글
지정된 디렉토리에 npm을 설치하는 방법은 무엇입니까? (0) | 2020.04.26 |
---|---|
ES6 약속이 있으므로 Q 또는 BlueBird와 같은 약속 라이브러리를 사용해야 할 이유가 있습니까? (0) | 2020.04.26 |
d3.js 시각화 레이아웃을 반응 형으로 만드는 가장 좋은 방법은 무엇입니까? (0) | 2020.04.26 |
Java 특성 파일을 사용하는 방법은 무엇입니까? (0) | 2020.04.26 |
JavaScript에서 세트를 모방합니까? (0) | 2020.04.26 |