Java는 다중 상속을 허용하지 않지만 다중 인터페이스를 구현할 수 있습니다. 왜?
Java는 다중 상속을 허용하지 않지만 다중 인터페이스를 구현할 수 있습니다. 왜?
답변:
인터페이스 만 지정하기 때문에 어떤 클래스가 아니라하고있다 어떻게 그것을하고있다.
다중 상속의 문제점은 두 클래스가 동일한 작업을 수행하는 다른 방법 을 정의 할 수 있으며 서브 클래스는 선택할 방법을 선택할 수 없다는 것입니다.
내 대학 강사 중 한 명이이 방법을 설명했습니다.
토스터 인 클래스 하나와 NuclearBomb 클래스가 있다고 가정 해 봅시다. 둘 다 "어둠"설정이있을 수 있습니다. 둘 다 on () 메소드를 가지고 있습니다. (하나는 off ()를 가지고 있고 다른 하나는 그렇지 않습니다.) 둘 다의 서브 클래스 인 클래스를 만들려면 여기에서 볼 수 있듯이 이것은 실제로 내 얼굴을 날려 버릴 수있는 문제입니다. .
따라서 주요 문제 중 하나는 부모 클래스가 두 개인 경우 강사의 예에서와 같이 동일한 기능의 다른 구현 또는 동일한 이름을 가진 두 개의 다른 기능을 가질 수 있다는 것입니다. 그런 다음 서브 클래스에서 사용할 클래스를 결정해야합니다. 이를 처리하는 방법은 확실히 있습니다. C ++도 마찬가지입니다. 그러나 Java 설계자들은 이것이 너무 복잡해질 것이라고 생각했습니다.
그러나 인터페이스를 사용하면 다른 클래스의 방법을 빌려주는 대신 클래스가 수행 할 수있는 것을 설명합니다. 다중 인터페이스는 다중 상위 클래스보다 해결해야하는 까다로운 충돌을 유발할 가능성이 훨씬 낮습니다.
"이봐, 그 방법은 유용 해 보인다. 나는 그 클래스도 확장 할 것이다"라고 말할 수 없을 때에도 상속이 과도하게 사용되기 때문이다 .
public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter,
AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...
이 질문에 대한 답은 java 컴파일러 (생성자 체인)의 내부 작업에 있습니다. Java 컴파일러의 내부 작업을 보면 :
public class Bank {
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank{
public void printBankBalance(){
System.out.println("20k");
}
}
이 컴파일 후 다음과 같습니다
public class Bank {
public Bank(){
super();
}
public void printBankBalance(){
System.out.println("10k");
}
}
class SBI extends Bank {
SBI(){
super();
}
public void printBankBalance(){
System.out.println("20k");
}
}
클래스를 확장하고 그 객체를 만들면 하나의 생성자 체인이 Object
클래스 까지 실행됩니다 .
위의 코드는 정상적으로 실행됩니다. 그러나 Car
확장 이라는 다른 클래스 Bank
와 하나의 하이브리드 (다중 상속) 클래스 가 있다면 SBICar
:
class Car extends Bank {
Car() {
super();
}
public void run(){
System.out.println("99Km/h");
}
}
class SBICar extends Bank, Car {
SBICar() {
super(); //NOTE: compile time ambiguity.
}
public void run() {
System.out.println("99Km/h");
}
public void printBankBalance(){
System.out.println("20k");
}
}
이 경우 (SBICar)는 생성자 체인을 생성하지 못합니다 ( 컴파일 시간 모호성 ).
인터페이스의 경우 객체를 만들 수 없으므로 허용됩니다.
새로운 개념 default
과 static
방법 에 대해서는 인터페이스에서 기본값을 참조하십시오 .
이것이 쿼리를 해결할 수 있기를 바랍니다. 감사.
여러 인터페이스를 구현하는 것은 매우 유용하며 언어 구현 자나 프로그래머에게 많은 문제를 일으키지 않습니다. 따라서 허용됩니다. 다중 상속도 유용하지만 사용자에게 심각한 문제를 일으킬 수 있습니다 ( 사망의 다이아몬드 ). 그리고 다중 상속으로 수행하는 대부분의 작업은 구성 또는 내부 클래스를 사용하여 수행 할 수도 있습니다. 따라서 여러 상속은 이익보다 더 많은 문제를 일으키는 것으로 금지됩니다.
ToyotaCar
및 HybridCar
모두에서 파생 Car
와 오버라이드 Car.Drive
한 경우 PriusCar
모두 상속 하지만 오버라이드 (override)하지 않은Drive
, 시스템은 가상이 무엇인지 식별 방법이 없을 것입니다 Car.Drive
해야합니다. 인터페이스는 위의 기울임 꼴 상태를 피하여이 문제를 방지합니다.
void UseCar(Car &foo)
; 사이 동음 포함 할 것으로 예상 할 수없는 ToyotaCar::Drive
및 HybridCar::Drive
(그 다른 유형도 있음을 종종 둘 다 알고 안 이후도 치료를 존재 ). C ++에서와 같이 언어는 코드 ToyotaCar &myCar
를 전달하려는 코드 UseCar
가 먼저 HybridCar
또는로 캐스트해야 ToyotaCar
하지만 ((Car) (HybridCar) myCar) .Drive 이후로 캐스트해야 하고 ((Car)(ToyotaCar)myCar).Drive
다른 작업을 수행해야합니다. 신원 보존이 아니었다.
다중 상속에 대한 오라클 문서 페이지에서이 쿼리에 대한 정확한 답변을 찾을 수 있습니다.
다중 상태 상속 : 여러 클래스에서 필드를 상속하는 기능
Java 프로그래밍 언어로 인해 둘 이상의 클래스를 확장 할 수없는 한 가지 이유는 여러 클래스에서 필드를 상속 할 수있는 다중 상태 상속 문제를 피하기위한 것입니다.
다중 상속이 허용되고 해당 클래스를 인스턴스화하여 객체를 만들면 해당 객체는 모든 클래스의 수퍼 클래스에서 필드를 상속합니다. 두 가지 문제가 발생합니다.
다중 구현 상속 : 다중 클래스에서 메소드 정의를 상속하는 기능
이 접근 방식의 문제점 : 이름 충돌 및 모호성 . 서브 클래스와 수퍼 클래스에 동일한 메소드 이름 (및 서명)이 포함되어 있으면 컴파일러는 호출 할 버전을 판별 할 수 없습니다.
그러나 Java는 Java 8 릴리스 이후에 도입 된 기본 메소드를 사용 하여 이러한 유형의 다중 상속을 지원합니다 . Java 컴파일러는 특정 클래스가 사용하는 기본 메소드를 판별하기위한 규칙을 제공합니다.
다이아몬드 문제 해결에 대한 자세한 내용은 아래 SE 게시물을 참조하십시오.
다중 상속 유형 : 하나 이상의 인터페이스를 구현할 수있는 클래스의 기능.
인터페이스에 변경 가능한 필드가 포함되어 있지 않으므로 여기에서 다중 상태 상속으로 인해 발생하는 문제에 대해 걱정할 필요가 없습니다.
객체 상태는 필드의 필드와 관련하여 참조되며 너무 많은 클래스가 상속되면 모호해질 수 있습니다. 여기 링크가 있습니다
http://docs.oracle.com/javase/tutorial/java/IandI/multipleinheritance.html
Java는 인터페이스를 통해서만 다중 상속을 지원합니다. 클래스는 여러 인터페이스를 구현할 수 있지만 하나의 클래스 만 확장 할 수 있습니다.
다중 상속은 치명적인 다이아몬드 문제로 이어지기 때문에 지원되지 않습니다. 그러나 해결할 수는 있지만 복잡한 시스템으로 이어 지므로 Java 설립자가 다중 상속을 중단했습니다.
1995 년 2 월 James Gosling의“Java : Overview”백서 ( link )에서는 Java에서 다중 상속이 지원되지 않는 이유에 대한 아이디어를 제공합니다.
고슬링에 따르면 :
"JAVA는 C ++의 거의 사용되지 않고 이해하기 어려운 혼란스러운 기능을 많이 사용하지 않아 경험에 비해 더 많은 슬픔을 겪습니다. 이는 주로 연산자 오버로드 (메소드 오버로드가 있지만), 다중 상속 및 광범위한 자동 강제로 구성됩니다."
같은 이유로 C #은 다중 상속을 허용하지 않지만 다중 인터페이스를 구현할 수 있습니다.
다중 상속을 통한 C ++에서 얻은 교훈은 가치보다 더 많은 문제가 발생한다는 것입니다.
인터페이스는 클래스가 구현해야하는 계약입니다. 인터페이스에서 기능을 얻지 못합니다. 상속을 사용하면 부모 클래스의 기능을 상속 할 수 있습니다 (다중 상속으로 인해 혼동 될 수 있음).
다중 인터페이스를 허용하면 어댑터와 같은 디자인 패턴을 사용하여 다중 상속을 사용하여 해결할 수있는 동일한 유형의 문제를 훨씬 더 안정적이고 예측 가능한 방식으로 해결할 수 있습니다.
D1
와 D2
에서 모두 상속 B
하고, 각 무시하는 기능이 f
있는 경우, 그리고 obj
유형의 인스턴스 S
에서 모두 상속 D1
하고 D2
있지만이 무시하지 않습니다가 f
, 다음에 대한 참조를 캐스팅 S
하기 위해 D1
뭔가 양보해야 f
사용 D1
재정의를, 그리고에 캐스팅 B
안 그것을 바꾸십시오. 마찬가지로 참조 S
를 캐스팅 하면 재정의 D2
를 f
사용 하는 것을 생성해야 D2
하며 캐스팅을 B
변경해서는 안됩니다. 언어가 가상 멤버를 추가 할 필요가없는 경우 ...
이 주제가 가깝지 않기 때문에이 답변을 게시 할 것이므로 java가 다중 상속을 허용하지 않는 이유를 누군가가 이해하는 데 도움이되기를 바랍니다.
다음 클래스를 고려하십시오.
public class Abc{
public void doSomething(){
}
}
이 경우 Abc 클래스는 아무것도 확장하지 않습니까? 그렇게 빠르지는 않지만이 클래스는 암시 적으로 모든 것을 작동시키는 기본 클래스 인 Object 클래스를 확장합니다. 모든 것이 대상입니다.
당신이 당신의 IDE는이 같은 방법을 사용할 수 있습니다 것을 볼 수 있습니다 위의 클래스를 사용하려고하면 : equals(Object o)
, toString()
, 등,하지만 당신은 그 방법을 선언하지 않았다, 그들은 기본 클래스에서 온Object
시도해 볼 수 있습니다 :
public class Abc extends String{
public void doSomething(){
}
}
이것은 클래스가 암시 적으로 확장 Object
되지는 않지만 String
말했기 때문에 확장 되기 때문에 좋습니다. 다음 변경 사항을 고려하십시오.
public class Abc{
public void doSomething(){
}
@Override
public String toString(){
return "hello";
}
}
toString ()을 호출하면 클래스는 항상 "hello"를 반환합니다.
이제 다음 수업을 상상해보십시오.
public class Flyer{
public void makeFly(){
}
}
public class Bird extends Abc, Flyer{
public void doAnotherThing(){
}
}
다시 클래스 Flyer
암시 적 확장 메소드를 가진 Object를 확장 toString()
합니다. 클래스는 모두 Object
간접적으로 확장 되므로이 메소드를 가지므로 toString()
from 을 호출 Bird
하면 어떤 toString()
java를 사용해야합니까? 에서 Abc
또는 Flyer
? 이것은 두 개 이상의 클래스를 확장하려고 시도하는 클래스에서 발생합니다. 이러한 종류의 "메소드 충돌"을 피하기 위해 인터페이스 개념을 만들었습니다 . 기본적으로 객체를 간접적으로 확장하지 않는 추상 클래스 로 생각할 수 있습니다 . 그것들은 추상적 이기 때문에 객체 인 클래스에 의해 구현되어야 합니다. (인터페이스를 단독으로 설치할 수는 없으며 클래스로 구현해야 함) 모든 것이 계속 잘 작동합니다.
인터페이스와 클래스를 구별하기 위해 키워드 구현 은 인터페이스 전용으로 예약되었습니다.
기본적으로 어떤 것도 확장하지 않기 때문에 같은 클래스에서 원하는 인터페이스를 구현할 수 있습니다 (그러나 다른 인터페이스를 확장하는 인터페이스를 만들 수 있지만 "father"인터페이스는 Object를 확장하지 않습니다). 따라서 인터페이스는 다음과 같습니다. 단지 인터페이스이고 " 메소드 서명 colissions "로 고통받지 않을 것입니다 . 컴파일러가 경고를 보내면 메소드 서명 을 변경하여 수정해야합니다 (서명 = 메소드 이름 + 매개 변수 + 반환 유형) .
public interface Flyer{
public void makeFly(); // <- method without implementation
}
public class Bird extends Abc implements Flyer{
public void doAnotherThing(){
}
@Override
public void makeFly(){ // <- implementation of Flyer interface
}
// Flyer does not have toString() method or any method from class Object,
// no method signature collision will happen here
}
인터페이스는 단지 계약이기 때문입니다. 그리고 클래스는 실제로 데이터의 컨테이너입니다.
예를 들어, 동일한 메소드 m1 ()을 갖는 2 개의 클래스 A, B. 그리고 클래스 C는 A, B를 모두 확장합니다.
class C extends A, B // for explaining purpose.
이제 클래스 C는 m1의 정의를 검색합니다. 먼저 찾지 못한 경우 수업에서 검색 한 다음 부모님 수업을 확인합니다. 정의를 갖는 A, B 둘 다 여기서 어떤 정의를 선택해야하는지 모호성이 발생합니다. 따라서 Java는 다중 상속을 지원하지 않습니다.
Java는 다음 두 가지 이유로 다중 상속을 지원하지 않습니다.
Object
. 둘 이상의 수퍼 클래스에서 상속되면 하위 클래스는 Object 클래스의 속성을 가져 오는 모호성을 얻습니다.super()
저녁 식사 클래스 생성자를 호출하기 위해 호출 됩니다. 클래스에 둘 이상의 수퍼 클래스가 있으면 혼동됩니다.따라서 하나의 클래스가 둘 이상의 수퍼 클래스에서 확장되면 컴파일 시간 오류가 발생합니다.
예를 들어 클래스 A에 getSomething 메소드가 있고 클래스 B에 getSomething 메소드가 있고 클래스 C가 A 및 B를 확장하는 경우를 예로 들어 보겠습니다. 누군가 C.getSomething이라고하면 어떻게 될까요? 어떤 메소드를 호출할지 결정할 방법이 없습니다.
인터페이스는 기본적으로 구현 클래스에 포함해야하는 메소드를 지정합니다. 여러 인터페이스를 구현하는 클래스는 클래스가 모든 해당 인터페이스의 메소드를 구현해야 함을 의미합니다. Whci는 위에서 설명한 문제를 일으키지 않습니다.
Java는 모호성 문제로 인해 다중 상속, 다중 경로 및 하이브리드 상속을 지원하지 않습니다.
Scenario for multiple inheritance: Let us take class A , class B , class C. class A has alphabet(); method , class B has also alphabet(); method. Now class C extends A, B and we are creating object to the subclass i.e., class C , so C ob = new C(); Then if you want call those methods ob.alphabet(); which class method takes ? is class A method or class B method ? So in the JVM level ambiguity problem occurred. Thus Java does not support multiple inheritance.
참조 링크 : https://plus.google.com/u/0/communities/102217496457095083679
간단한 방법으로 우리는 하나의 클래스를 상속 (extends) 할 수 있지만 너무 많은 인터페이스를 구현할 수 있습니다. java가 너무 많은 클래스를 확장 할 수 있고 동일한 메소드를 가지고 있다고 가정하십시오.이 시점에서 서브 클래스에서 수퍼 클래스 메소드를 호출하려고하면 어떤 메소드를 실행해야합니까 ??, 컴파일러가 혼란스러워합니다. 예 :-여러 확장을 시도 하지만 이러한 메소드에는 서브 클래스에서 구현해야하는 바디가 없습니다. 여러 개의 구현을 시도 하므로 걱정할 필요 가 없습니다.
* 이것은 Java 초보자이기 때문에 간단한 답변입니다 *
세 가지 클래스가 고려 X
, Y
과 Z
.
우리가 같이 상속하는 그래서 X extends Y, Z
모두 Y
와 Z
방법 데 alphabet()
같은 반환 형식 및 인수를. 이 방법 alphabet()
으로는 Y
말한다 첫번째 알파벳 표시 및에 방법 알파벳 Z
라고 표시 마지막 알파벳 . 에 alphabet()
의해 호출 될 때 모호함이 여기에 온다 X
. 첫 알파벳 또는 마지막 알파벳 을 표시 할 것인지 여부 따라서 java는 다중 상속을 지원하지 않습니다. 인터페이스의 경우, 고려 Y
및 Z
인터페이스와 같은. 따라서 둘 다 메소드 선언을 포함 alphabet()
하지만 정의 는 포함 하지 않습니다. 첫 알파벳이나 마지막 알파벳을 표시할지 여부를 알려주지 않고 메소드를 선언합니다.alphabet()
. 따라서 모호성을 높일 이유가 없습니다. class 내부에서 원하는 것을 사용하여 메소드를 정의 할 수 있습니다 X
.
한마디로 인터페이스 정의에서 구현 후 수행되므로 혼란이 없습니다.