Tại sao không có nhiều kế thừa trong Java, nhưng thực hiện nhiều giao diện được cho phép?


153

Java không cho phép nhiều kế thừa, nhưng nó cho phép thực hiện nhiều giao diện. Tại sao?


1
Tôi chỉnh sửa tiêu đề câu hỏi để làm cho nó mô tả nhiều hơn.
Bozho

4
Thật thú vị, trong JDK 8, sẽ có các phương thức mở rộng cho phép định nghĩa về việc thực hiện các phương thức giao diện. Các quy tắc được xác định để chi phối nhiều kế thừa hành vi, nhưng không phải là trạng thái (mà tôi hiểu là có vấn đề hơn .
Edwin Dalorzo

1
Trước khi các bạn lãng phí thời gian vào các câu trả lời chỉ cho bạn biết "Làm thế nào java đạt được nhiều sự thừa kế" ... Tôi khuyên bạn nên đi xuống câu trả lời @Prabal Srivastava cung cấp cho bạn những gì phải xảy ra trong nội bộ, để không cho phép các lớp này đúng .. và chỉ cho phép giao diện quyền cho phép nhiều kế thừa.
Ứng dụng Yo

Câu trả lời:


228

Bởi vì các giao diện chỉ xác định những gì lớp đang làm, không phải nó đang làm như thế nào .

Vấn đề với nhiều kế thừa là hai lớp có thể định nghĩa các cách khác nhau để thực hiện cùng một thứ và lớp con không thể chọn cái nào để chọn.


8
Tôi đã từng làm C ++ và gặp vấn đề chính xác tương tự một vài lần. Gần đây tôi đã đọc về Scala có "đặc điểm" đối với tôi có vẻ như có gì đó ở giữa cách "C ++" và cách làm "Java".
Niels Basjes

2
Bằng cách này, bạn đang tránh được "vấn đề kim cương": en.wikipedia.org/wiki/Diamond_pro Hiệu
Nick L.

6
Vì Java 8, bạn có thể định nghĩa hai phương thức mặc định giống hệt nhau, một phương thức trong mỗi giao diện. Nếu bạn sẽ triển khai cả hai giao diện trong lớp của mình, bạn phải ghi đè phương thức này trong chính lớp đó, xem: docs.oracle.com/javase/tutorial/java/IandI/ trộm
bobbel

6
Câu trả lời này không chính xác. Vấn đề là không chỉ rõ cách thức và Java 8 ở đó để chứng minh. Trong Java 8, hai siêu giao diện có thể khai báo cùng một phương thức với các cách triển khai khác nhau, nhưng đó không phải là vấn đề vì các phương thức giao diện là ảo , vì vậy bạn chỉ có thể ghi đè lên chúng và vấn đề được giải quyết. Vấn đề thực sự là về sự mơ hồ trong các thuộc tính , bởi vì bạn không thể giải quyết sự mơ hồ này ghi đè lên thuộc tính (thuộc tính không phải là ảo).
Alex Oliveira

1
"Thuộc tính" nghĩa là gì?
Bozho

96

Một trong những giảng viên đại học của tôi đã giải thích cho tôi theo cách này:

Giả sử tôi có một lớp, đó là Máy nướng bánh mì, và một lớp khác, đó là NucleBomb. Cả hai có thể có một thiết lập "bóng tối". Cả hai đều có một phương thức on (). (Một người đã tắt (), người kia thì không.) Nếu tôi muốn tạo một lớp đó là một lớp con của cả hai ... như bạn có thể thấy, đây là một vấn đề thực sự có thể xảy ra ở mặt tôi ở đây .

Vì vậy, một trong những vấn đề chính là nếu bạn có hai lớp cha, chúng có thể có các cách triển khai khác nhau của cùng một tính năng - hoặc có thể là hai tính năng khác nhau có cùng tên, như trong ví dụ của người hướng dẫn của tôi. Sau đó, bạn phải đối phó với việc quyết định lớp con nào sẽ sử dụng. Chắc chắn có nhiều cách để xử lý việc này - C ++ làm như vậy - nhưng các nhà thiết kế của Java cảm thấy rằng điều này sẽ khiến mọi thứ trở nên quá phức tạp.

Mặc dù vậy, với một giao diện, bạn đang mô tả một cái gì đó mà lớp có khả năng thực hiện, thay vì mượn phương thức làm của một lớp khác. Nhiều giao diện ít có khả năng gây ra xung đột phức tạp cần được giải quyết hơn là nhiều lớp cha.


5
Cảm ơn, NomeN. Nguồn trích dẫn là một nghiên cứu sinh tên là Brendan Burns, người lúc đó cũng là người duy trì kho lưu trữ nguồn Quake 2 nguồn mở. Đi hình.
Cú pháp

4
Vấn đề với sự tương tự này là nếu bạn đang tạo ra một lớp con của bom hạt nhân và máy nướng bánh mì, "máy nướng bánh mì hạt nhân" sẽ nổ tung một cách hợp lý khi được sử dụng.
101100

20
Nếu ai đó quyết định trộn một quả bom hạt nhân và máy nướng bánh mì, anh ta xứng đáng với quả bom đó nổ tung trên mặt. Câu trích dẫn là lý luận
ngụy biện

1
Cùng một ngôn ngữ lập trình cho phép thừa kế nhiều "giao diện", vì vậy "biện minh" này không áp dụng.
tò mò

24

Bởi vì tính kế thừa được sử dụng quá mức ngay cả khi bạn không thể nói "này, phương pháp đó có vẻ hữu ích, tôi cũng sẽ mở rộng lớp đó".

public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter, 
             AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...

Bạn có thể giải thích lý do tại sao bạn nói thừa kế bị lạm dụng? Tạo một lớp thần là chính xác những gì tôi muốn làm! Tôi tìm thấy rất nhiều người làm việc xung quanh kế thừa đơn bằng cách tạo các lớp "Công cụ" có các phương thức tĩnh.
Duncan Calvert

9
@DuncanCalvert: Không, bạn không muốn làm điều đó, không phải nếu mã đó sẽ cần bảo trì. Rất nhiều phương thức tĩnh bỏ lỡ điểm OO, nhưng thừa kế quá mức sẽ tệ hơn nhiều vì bạn hoàn toàn không biết mã nào được sử dụng ở đâu, cũng như về mặt khái niệm của lớp. Cả hai đang cố gắng giải quyết vấn đề "làm thế nào tôi có thể sử dụng mã này khi tôi cần nó", nhưng đó là một vấn đề ngắn hạn đơn giản. Vấn đề dài hạn khó hơn nhiều được giải quyết bằng thiết kế OO thích hợp là "làm cách nào để thay đổi mã này mà không bị vỡ chương trình ở 20 nơi khác nhau theo những cách không lường trước được?
Michael Borgwardt

2
@DuncanCalvert: và bạn giải quyết điều đó bằng cách có các lớp có độ kết dính cao và độ khớp thấp, có nghĩa là chúng chứa các phần dữ liệu và mã tương tác mạnh với nhau, nhưng chỉ tương tác với phần còn lại của chương trình thông qua API công khai nhỏ, đơn giản. Sau đó, bạn có thể suy nghĩ về chúng theo API đó thay vì các chi tiết bên trong, điều này rất quan trọng vì mọi người chỉ có thể ghi nhớ một số lượng chi tiết hạn chế cùng một lúc.
Michael Borgwardt

18

Câu trả lời của câu hỏi này nằm ở hoạt động bên trong của trình biên dịch java (chuỗi xây dựng). Nếu chúng ta thấy hoạt động nội bộ của trình biên dịch java:

public class Bank {
  public void printBankBalance(){
    System.out.println("10k");
  }
}
class SBI extends Bank{
 public void printBankBalance(){
    System.out.println("20k");
  }
}

Sau khi biên dịch, giao diện này giống như:

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

Khi chúng ta mở rộng lớp và tạo một đối tượng của nó, một chuỗi hàm tạo sẽ chạy cho đến Object lớp.

Mã trên sẽ chạy tốt. nhưng nếu chúng ta có một lớp khác được gọi là lớp Carmở rộng Bankvà một lớp lai (nhiều kế thừa) được gọi là 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");
  }
}

Trong trường hợp này (SBICar) sẽ không tạo được chuỗi xây dựng ( biên dịch thời gian mơ hồ ).

Đối với các giao diện, điều này được cho phép bởi vì chúng ta không thể tạo một đối tượng của nó.

Đối với khái niệm mới defaultstaticphương pháp vui lòng tham khảo mặc định trong giao diện .

Hy vọng điều này sẽ giải quyết câu hỏi của bạn. Cảm ơn.


7

Việc triển khai nhiều giao diện rất hữu ích và không gây ra nhiều vấn đề cho người thực hiện ngôn ngữ cũng như lập trình viên. Vì vậy, nó được cho phép. Nhiều kế thừa trong khi cũng hữu ích, có thể gây ra vấn đề nghiêm trọng cho người dùng (sợ hãi kim cương ). Và hầu hết những điều bạn làm với nhiều kế thừa cũng có thể được thực hiện bằng cách sáng tác hoặc sử dụng các lớp bên trong. Vì vậy, nhiều kế thừa bị cấm mang lại nhiều vấn đề hơn lợi ích.


Vấn đề với "viên kim cương tử thần" là gì?
tò mò

2
@cquilguy Chứa nhiều hơn một tiểu dự án của cùng một lớp cơ sở, sự không rõ ràng (ghi đè từ đó sử dụng lớp cơ sở), các quy tắc phức tạp để giải quyết sự mơ hồ đó.
Tadeusz Kopec

@cquilguy: Nếu một khung công tác cung cấp rằng việc truyền tham chiếu đối tượng đến tham chiếu kiểu cơ sở sẽ được bảo toàn danh tính, thì mọi đối tượng đối tượng phải có chính xác một triển khai của bất kỳ phương thức lớp cơ sở nào. Nếu ToyotaCarHybridCarcả hai xuất phát từ Carvà overrode Car.Drive, và nếu PriusCarđược thừa hưởng cả hai nhưng không ghi đèDrive , hệ thống sẽ không có cách nào để xác định những gì ảo Car.Drivenên làm. Các giao diện tránh vấn đề này bằng cách tránh các điều kiện in nghiêng ở trên.
supercat

1
@supercat "hệ thống sẽ không có cách nào để xác định Car.Drive ảo nên làm gì." <- Hoặc nó chỉ có thể đưa ra một lỗi biên dịch và khiến bạn chọn một lỗi rõ ràng, giống như C ++.
Chris Middleton

1
@ChrisMiddleton: Một phương pháp void UseCar(Car &foo); không thể được dự kiến ​​sẽ bao gồm sự định hướng giữa ToyotaCar::DriveHybridCar::Drive(vì nó thường không biết và cũng không quan tâm rằng những loại khác thậm chí còn tồn tại ). Một ngôn ngữ có thể, như C ++ không, yêu cầu mã với ToyotaCar &myCarnhu cầu để vượt qua nó để UseCarphải cast đầu tiên cho một trong hai HybridCarhoặc ToyotaCar, nhưng kể từ khi ((Xe) (HybridCar) myCar) .Drive` và ((Car)(ToyotaCar)myCar).Drive sẽ làm những việc khác nhau, mà có ngụ ý rằng upcasts không bảo tồn danh tính.
supercat

6

Bạn có thể tìm thấy câu trả lời chính xác cho truy vấn này trong trang tài liệu oracle về nhiều kế thừa

  1. Nhiều kế thừa trạng thái: Khả năng kế thừa các trường từ nhiều lớp

    Một lý do tại sao ngôn ngữ lập trình Java không cho phép bạn mở rộng nhiều hơn một lớp là để tránh các vấn đề về thừa kế trạng thái, đó là khả năng kế thừa các trường từ nhiều lớp

    Nếu nhiều kế thừa được cho phép và Khi bạn tạo một đối tượng bằng cách khởi tạo lớp đó, đối tượng đó sẽ kế thừa các trường từ tất cả các siêu lớp của lớp. Nó sẽ gây ra hai vấn đề.

    1. Điều gì xảy ra nếu các phương thức hoặc hàm tạo từ các siêu lớp khác nhau khởi tạo cùng một trường?
    2. Phương pháp hoặc nhà xây dựng nào sẽ được ưu tiên?
  2. Đa kế thừa thực hiện: Khả năng kế thừa các định nghĩa phương thức từ nhiều lớp

    Các vấn đề với cách tiếp cận này: tên xung đột ts và sự mơ hồ . Nếu một lớp con và siêu lớp chứa cùng tên phương thức (và chữ ký), trình biên dịch không thể xác định phiên bản nào sẽ gọi.

    Nhưng java hỗ trợ kiểu thừa kế đa dạng này với các phương thức mặc định , đã được giới thiệu kể từ khi phát hành Java 8. Trình biên dịch Java cung cấp một số quy tắc để xác định phương thức mặc định mà một lớp cụ thể sử dụng.

    Tham khảo bài viết dưới đây của SE để biết thêm chi tiết về cách giải quyết vấn đề kim cương:

    Sự khác biệt giữa các lớp trừu tượng và giao diện trong Java 8 là gì?

  3. Nhiều kiểu thừa kế: Khả năng của một lớp để thực hiện nhiều giao diện.

    Vì giao diện không chứa các trường có thể thay đổi, bạn không phải lo lắng về các vấn đề phát sinh từ nhiều kế thừa trạng thái ở đây.



4

Java chỉ hỗ trợ nhiều kế thừa thông qua các giao diện. Một lớp có thể thực hiện bất kỳ số lượng giao diện nào nhưng chỉ có thể mở rộng một lớp.

Nhiều kế thừa không được hỗ trợ vì nó dẫn đến vấn đề kim cương chết người. Tuy nhiên, nó có thể được giải quyết nhưng nó dẫn đến hệ thống phức tạp nên nhiều kế thừa đã bị các nhà sáng lập Java bỏ.

Trong một tờ giấy trắng có tựa đề Java Java: Tổng quan về James của James Gosling vào tháng 2 năm 1995 ( liên kết ) đưa ra một ý tưởng về lý do tại sao nhiều kế thừa không được hỗ trợ trong Java.

Theo Gosling:

"JAVA bỏ qua nhiều tính năng hiếm khi được sử dụng, hiểu kém, khó hiểu của C ++ mà theo kinh nghiệm của chúng tôi mang lại nhiều đau buồn hơn lợi ích. Điều này chủ yếu bao gồm quá tải toán tử (mặc dù nó có quá tải phương thức), nhiều kế thừa và ép buộc tự động mở rộng."


liên kết không thể truy cập. Vui lòng kiểm tra và cập nhật nó.
MashukKhan

3

Vì lý do tương tự, C # không cho phép nhiều kế thừa nhưng cho phép bạn triển khai nhiều giao diện.

Bài học rút ra từ C ++ với nhiều sự kế thừa là nó dẫn đến nhiều vấn đề hơn giá trị của nó.

Một giao diện là một hợp đồng của những thứ mà lớp của bạn phải thực hiện. Bạn không đạt được bất kỳ chức năng nào từ giao diện. Kế thừa cho phép bạn kế thừa chức năng của lớp cha (và trong đa kế thừa, điều đó có thể trở nên cực kỳ khó hiểu).

Cho phép nhiều giao diện cho phép bạn sử dụng Mẫu thiết kế (như Bộ điều hợp) để giải quyết các loại vấn đề giống nhau mà bạn có thể giải quyết bằng cách sử dụng nhiều kế thừa, nhưng theo cách đáng tin cậy và dễ đoán hơn nhiều.


10
C # không có nhiều kế thừa chính xác vì Java không cho phép nó. Nó được thiết kế muộn hơn nhiều so với Java. Vấn đề chính với nhiều sự kế thừa tôi nghĩ là cách mọi người được dạy sử dụng nó trái và phải. Khái niệm ủy nhiệm trong hầu hết các trường hợp là một sự thay thế tốt hơn nhiều chỉ không có ở đầu và giữa những năm 1990. Do đó tôi nhớ các ví dụ, trong sách giáo khoa, khi Xe là Bánh xe và Cửa và Kính chắn gió, so với Xe có Bánh xe, Cửa và Kính chắn gió. Vì vậy, sự kế thừa duy nhất trong Java là một phản ứng giật đầu gối với thực tế đó.
Alexander Pogrebnyak

2
@AlexanderPogrebnyak: Chọn hai trong ba điều sau đây: (1) Cho phép các biểu mẫu bảo toàn danh tính từ một tham chiếu kiểu con đến một tham chiếu siêu kiểu; (2) Cho phép một lớp thêm các thành viên ảo mà không cần biên dịch lại các lớp dẫn xuất; (3) Cho phép một lớp hoàn toàn kế thừa các thành viên ảo từ nhiều lớp cơ sở mà không cần phải chỉ định rõ ràng chúng. Tôi không tin bất kỳ ngôn ngữ nào có thể quản lý cả ba điều trên. Java đã chọn cho phù hợp với # 1 và # 2 và C # theo sau. Tôi tin rằng C ++ chỉ chấp nhận # 3. Cá nhân, tôi nghĩ # 1 và # 2 hữu ích hơn # 3, nhưng những người khác có thể khác nhau.
supercat

@supercat "Tôi không tin bất kỳ ngôn ngữ nào có thể quản lý cả ba điều trên" - nếu độ lệch của các thành viên dữ liệu được xác định trong thời gian chạy, thay vì thời gian biên dịch (vì chúng nằm trong ABI "không mong manh" của Objective-C ") Và hoặc cơ sở cho mỗi lớp (tức là mỗi lớp cụ thể có bảng bù thành viên riêng), thì tôi nghĩ rằng cả 3 mục tiêu đều có thể đạt được.
Croissant Paramag từ

@TheParamag từCroissant: Vấn đề ngữ nghĩa chính là # 1. Nếu D1D2đều kế thừa từ B, và mỗi ghi đè một chức năng f, và nếu objlà một thể hiện của một kiểu Smà thừa hưởng từ cả hai D1D2nhưng không ghi đè lên f, sau đó đúc một tham chiếu đến Sđể D1nên mang một cái gì đó mà fsử dụng các D1ghi đè và đúc để Bkhông nên thay đổi điều đó. Tương tự, truyền tham chiếu Sđể D2mang lại một cái gì đó fsử dụng D2ghi đè và truyền để Bkhông thay đổi điều đó. Nếu một ngôn ngữ không cần cho phép thêm thành viên ảo ...
supercat

1
@TheParamag từCroissant: Có thể, và danh sách các lựa chọn của tôi có phần bị đơn giản hóa quá mức để phù hợp với một nhận xét, nhưng việc trì hoãn thời gian chạy khiến tác giả của D1, D2 hoặc S không thể biết những thay đổi nào họ có thể thực hiện mà không phá vỡ người tiêu dùng của lớp họ.
supercat

2

Vì chủ đề này không gần nên tôi sẽ đăng câu trả lời này, tôi hy vọng điều này sẽ giúp ai đó hiểu tại sao java không cho phép nhiều kế thừa.

Hãy xem xét các lớp sau:

public class Abc{

    public void doSomething(){

    }

}

Trong trường hợp này, lớp Abc không mở rộng được gì phải không? Không quá nhanh, lớp này ngầm mở rộng lớp Object, lớp cơ sở cho phép mọi thứ hoạt động trong java. Tất cả mọi thứ là một đối tượng.

Nếu bạn cố gắng sử dụng các lớp ở trên, bạn sẽ thấy rằng IDE của bạn cho phép bạn sử dụng các phương pháp như: equals(Object o), toString(), vv, nhưng bạn đã không khai báo các phương pháp đó, họ đến từ các lớp cơ sởObject

Bạn có thể thử:

public class Abc extends String{

    public void doSomething(){

    }

}

Điều này là tốt, bởi vì lớp học của bạn sẽ không ngầm kéo dài Objectmà sẽ mở rộng Stringvì bạn đã nói nó. Hãy xem xét sự thay đổi sau đây:

public class Abc{

    public void doSomething(){

    }

    @Override
    public String toString(){
        return "hello";
    }

}

Bây giờ lớp của bạn sẽ luôn trả về "xin chào" nếu bạn gọi toString ().

Bây giờ hãy tưởng tượng lớp sau:

public class Flyer{

    public void makeFly(){

    }

}

public class Bird extends Abc, Flyer{

    public void doAnotherThing(){

    }

}

Một lần nữa lớp Flyerngầm mở rộng Object có phương thức toString(), bất kỳ lớp nào cũng sẽ có phương thức này vì tất cả chúng đều mở rộng Objectgián tiếp, vì vậy, nếu bạn gọi toString()từ Bird, toString()java nào sẽ phải sử dụng? Từ Abchay Flyer? Điều này sẽ xảy ra với bất kỳ lớp nào cố gắng mở rộng hai hoặc nhiều lớp, để tránh loại "xung đột phương thức" này, họ đã xây dựng ý tưởng về giao diện , về cơ bản bạn có thể nghĩ chúng là một lớp trừu tượng không mở rộng đối tượng một cách gián tiếp . Vì chúng là trừu tượng nên chúng sẽ phải được thực hiện bởi một lớp, đó là một đối tượng(bạn không thể kích hoạt giao diện một mình, chúng phải được thực hiện bởi một lớp), vì vậy mọi thứ sẽ tiếp tục hoạt động tốt.

Để khác các lớp từ giao diện, từ khóa thực hiện chỉ dành riêng cho giao diện.

Bạn có thể triển khai bất kỳ giao diện nào bạn thích trong cùng một lớp vì chúng không mở rộng bất cứ thứ gì theo mặc định (nhưng bạn có thể tạo giao diện mở rộng giao diện khác, nhưng một lần nữa, giao diện "cha" sẽ không mở rộng Object "), vì vậy giao diện là chỉ là một giao diện và họ sẽ không phải chịu " dấu hiệu chữ ký phương thức ", nếu họ thực hiện trình biên dịch sẽ đưa ra cảnh báo cho bạn và bạn sẽ phải thay đổi chữ ký phương thức để sửa nó (chữ ký = tên phương thức + params + kiểu trả về) .

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

}

1

Bởi vì một giao diện chỉ là một hợp đồng. Và một lớp thực sự là một thùng chứa dữ liệu.


Khó khăn cơ bản với nhiều kế thừa là khả năng một lớp có thể kế thừa một thành viên thông qua nhiều đường dẫn thực hiện nó khác nhau, mà không cung cấp thực thi ghi đè của chính nó. Kế thừa giao diện tránh điều này bởi vì các thành viên giao diện nơi duy nhất có thể được thực hiện là trong các lớp, con cháu của chúng sẽ bị giới hạn trong kế thừa đơn.
supercat

1

Ví dụ hai lớp A, B có cùng phương thức m1 (). Và lớp C mở rộng cả A, B.

 class C extends A, B // for explaining purpose.

Bây giờ, lớp C sẽ tìm kiếm định nghĩa của m1. Đầu tiên, nó sẽ tìm kiếm trong lớp nếu nó không tìm thấy thì nó sẽ kiểm tra lớp phụ huynh. Cả A, B đều có định nghĩa Vì vậy, ở đây sự mơ hồ xảy ra nên chọn định nghĩa nào. Vì vậy, JAVA KHÔNG HPORT TRỢ NHIỀU NỀN TẢNG.


Làm thế nào về việc tạo trình biên dịch java cung cấp trình biên dịch nếu cùng các phương thức hoặc biến được định nghĩa trong cả hai lớp cha mẹ để chúng ta có thể thay đổi mã ...
siluveru kiran kumar

1

Java không hỗ trợ nhiều kế thừa vì hai lý do:

  1. Trong java, mỗi lớp là một đứa trẻ của Objectlớp. Khi nó kế thừa từ nhiều hơn một siêu lớp, lớp con có được sự mơ hồ để có được thuộc tính của lớp Object ..
  2. Trong java mỗi lớp có một hàm tạo, nếu chúng ta viết nó rõ ràng hay không. Câu lệnh đầu tiên đang gọi super()để gọi hàm tạo của lớp supper. Nếu lớp có nhiều hơn một siêu lớp, nó sẽ bị lẫn lộn.

Vì vậy, khi một lớp mở rộng từ nhiều hơn một siêu lớp, chúng ta sẽ gặp lỗi thời gian biên dịch.


0

Lấy ví dụ như trường hợp Class A có phương thức getS Something và lớp B có phương thức getS Something và lớp C mở rộng A và B. Điều gì sẽ xảy ra nếu ai đó gọi là C.getS Something? Không có cách nào để xác định phương thức nào để gọi.

Các giao diện về cơ bản chỉ xác định các phương thức mà lớp triển khai cần chứa. Một lớp thực hiện nhiều giao diện chỉ có nghĩa là lớp đó phải thực hiện các phương thức từ tất cả các giao diện đó. Whci sẽ không dẫn đến bất kỳ vấn đề như mô tả ở trên.


2
" Điều gì sẽ xảy ra nếu ai đó gọi là C.getS Something. " Đó là một lỗi trong C ++. Vấn đề được giải quyết.
tò mò

Đó là điểm ... đó là một ví dụ phản biện mà tôi nghĩ là rõ ràng. Tôi đã chỉ ra rằng không có cách nào để xác định phương thức nào nên được gọi. Cũng như một ghi chú bên lề, câu hỏi có liên quan đến java chứ không phải c ++
John Kane

Tôi xin lỗi tôi không hiểu ý của bạn là gì. Rõ ràng, có sự mơ hồ trong một số trường hợp với MI. Làm thế nào là một ví dụ truy cập? Ai tuyên bố rằng MI không bao giờ dẫn đến sự mơ hồ? " Cũng như một ghi chú bên lề, câu hỏi có liên quan đến java không phải c ++ " Vậy sao?
tò mò

Tôi chỉ cố gắng chỉ ra tại sao sự mơ hồ đó tồn tại và tại sao nó không có giao diện.
John Kane

Có, MI có thể dẫn đến các cuộc gọi mơ hồ. Như vậy có thể quá tải. Vì vậy, Java nên loại bỏ quá tải?
tò mò

0

Hãy xem xét một kịch bản trong đó Test1, Test2 và Test3 là ba lớp. Lớp Test3 kế thừa các lớp Test2 và Test1. Nếu các lớp Test1 và Test2 có cùng một phương thức và bạn gọi nó từ đối tượng lớp con, sẽ có sự mơ hồ khi gọi phương thức của lớp Test1 hoặc Test2 nhưng không có sự mơ hồ nào về giao diện như trong giao diện không có triển khai.


0

Java không hỗ trợ nhiều kế thừa, đa đường và thừa kế lai do vấn đề không rõ ràng:

 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.

đa thừa kế

Liên kết tham khảo: https://plus.google.com/u/0/cransities/102217496457095083679


0

theo cách đơn giản, tất cả chúng ta đều biết, chúng ta có thể kế thừa (mở rộng) một lớp nhưng chúng ta có thể thực hiện rất nhiều giao diện .. đó là vì trong các giao diện chúng ta không đưa ra một triển khai chỉ nói chức năng. giả sử nếu java có thể mở rộng rất nhiều lớp và những lớp đó có cùng phương thức .. thì ở điểm này nếu chúng ta cố gắng gọi phương thức siêu lớp trong lớp con thì phương thức nào giả sử để chạy ??, trình biên dịch lấy ví dụ nhầm lẫn : - thử nhiều lần mở rộng nhưng trong giao diện những phương thức không có cơ thể chúng ta nên thực hiện những phương thức trong lớp con .. cố gắng thực hiện nhiều công cụ để không phải lo lắng ..


1
Bạn chỉ có thể đăng ở đây những ví dụ. Không có điều này trông giống như một khối văn bản cho câu hỏi 9 tuổi được trả lời hàng trăm lần.
Pochmurnik

-1

* Đây là một câu trả lời đơn giản vì tôi là người mới bắt đầu sử dụng Java *

Hãy xem xét có ba lớp X, YZ.

Vì vậy, chúng tôi đang kế thừa like X extends Y, Z Và cả hai YZđang có một phương thức alphabet()có cùng kiểu trả về và đối số. Phương pháp này alphabet()trong Ynói với hiển thị bảng chữ cái đầu tiên và phương pháp bảng chữ cái trong Znói hiển thị bảng chữ cái cuối cùng . Vì vậy, ở đây mơ hồ khi alphabet()được gọi bởi X. Cho dù nó nói để hiển thị bảng chữ cái đầu tiên hoặc cuối cùng ??? Vì vậy, java không hỗ trợ nhiều kế thừa. Trong trường hợp Giao diện, hãy xem xét YZnhư giao diện. Vì vậy, cả hai sẽ chứa khai báo phương thức alphabet()nhưng không định nghĩa. Nó sẽ không cho biết liệu hiển thị bảng chữ cái đầu tiên hoặc bảng chữ cái cuối cùng hoặc bất cứ điều gì nhưng sẽ chỉ tuyên bố một phương thứcalphabet(). Vì vậy, không có lý do để nâng cao sự mơ hồ. Chúng ta có thể định nghĩa phương thức với bất cứ thứ gì chúng ta muốn trong lớp X.

Vì vậy, trong một từ, trong định nghĩa Giao diện được thực hiện sau khi thực hiện để không nhầm lẫn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.