Làm thế nào để các Giao diện Java mô phỏng đa kế thừa?


76

Tôi đang đọc "Hướng dẫn Java" (lần thứ 2). Tôi vừa xem qua phần Giao diện (một lần nữa), nhưng vẫn chưa hiểu cách Giao diện Java mô phỏng đa kế thừa. Có lời giải thích rõ ràng hơn những gì trong sách không?



Bài đăng trên blog này đã giải thích cách đạt được đa kế thừa. erik-rasmussen.com/blog/2006/10/23/multiple-inheritance-in-java
Rakesh Juyal

3
@Tom: theo "Hướng dẫn Java", (ấn bản thứ 4 p142) "Trong Java, một lớp chỉ có thể kế thừa từ một lớp nhưng nó có thể triển khai nhiều hơn một giao diện. Do đó, các đối tượng có thể có nhiều kiểu: kiểu của riêng chúng lớp và kiểu của tất cả các giao diện mà chúng triển khai. Điều này có nghĩa là nếu một biến được khai báo là kiểu của giao diện, giá trị của nó có thể tham chiếu đến bất kỳ đối tượng nào được khởi tạo từ bất kỳ lớp nào triển khai giao diện. " Tác giả đã đánh mất tôi ở câu cuối cùng nhưng những giải thích ở đây (hầu hết) đã làm sáng tỏ nó.
jacknad

Câu trả lời:


154

Giả sử bạn có 2 loại thứ trong miền của mình: Xe tải và Nhà bếp

Xe tải có phương thức driveTo () và phương thức Kitchens a cook ().

Bây giờ, giả sử Pauli quyết định bán pizza từ phía sau xe tải giao hàng. Anh ấy muốn một thứ mà anh ấy có thể lái xeTo () và nấu ăn () với.

Trong C ++, anh ấy sẽ sử dụng đa kế thừa để làm điều này.

Trong Java, điều đó được coi là quá nguy hiểm nên bạn có thể kế thừa từ một lớp chính, nhưng bạn có thể "kế thừa" các hành vi từ các giao diện, dành cho tất cả các mục đích và mục đích, các lớp trừu tượng không có trường hoặc triển khai phương thức.

Vì vậy, trong Java, chúng tôi có xu hướng triển khai đa kế thừa bằng cách sử dụng các ủy quyền:

Pauli phân loại một chiếc xe tải và thêm một nhà bếp vào chiếc xe tải trong một biến thành viên được gọi là nhà bếp. Anh ta cài đặt giao diện Kitchen bằng cách gọi cook.cook ().

class PizzaTruck extends Truck implements Kitchen {
   Kitchen kitchen;

   public void cook(Food foodItem) {
      kitchen.cook(foodItem);
   }
}

Anh ấy là một người đàn ông hạnh phúc vì bây giờ anh ấy có thể làm những việc như;

pizzaTruck.driveTo(beach);
pizzaTruck.cook(pizzaWithExtraAnchovies);

Được rồi, câu chuyện ngớ ngẩn này là để làm rõ rằng nó không phải là mô phỏng của đa kế thừa, nó là đa kế thừa thực sự với điều kiện là bạn chỉ có thể kế thừa hợp đồng, chỉ kế thừa từ các lớp cơ sở trừu tượng trống được gọi là giao diện.

(cập nhật: với sự xuất hiện của các giao diện phương thức mặc định bây giờ cũng có thể cung cấp một số hành vi được kế thừa)


8
điều gì sẽ xảy ra nếu Kitchen không phải là một giao diện mà là một lớp khác?
Bizmarck

2
@bizmark: Sau đó, tạo một giao diện Cookery (với public void cook()) mà cả Kitchen và PizzaTruck sẽ triển khai.
splungebob

10
Điều gì sẽ xảy ra nếu cả Xe tải và Nhà bếp đều là các lớp có các trường và chúng ta cần tất cả các trường đó trong PizzaTruck? ví dụ để thực hiện PizzaTruck.shootPizzasBackwards (), làm giảm PizzaCount (A lĩnh vực nhà bếp) và tăng tốc độ (A lĩnh vực xe tải)
Hello World


1
Mặc dù đúng vào năm 2010, "... dành cho mọi ý định và mục đích các lớp trừu tượng không có trường hoặc triển khai phương thức ..." không còn đúng nữa, nhờ defaultcác phương thức. Giao diện vẫn không có nhà nước chẳng hạn, nhưng họ làm có phương pháp một lớp có thể kế thừa.
TJ Crowder

19

Có thể bạn đang nhầm lẫn vì bạn xem cục bộ đa kế thừa, trong điều kiện một lớp kế thừa chi tiết triển khai từ nhiều lớp cha mẹ. Điều này là không thể trong Java (và thường dẫn đến lạm dụng trong các ngôn ngữ có thể xảy ra).

Các giao diện cho phép đa kế thừa các kiểu , ví dụ a class Waterfowl extends Bird implements Swimmercó thể được sử dụng bởi các lớp khác như thể nó là a Bird như thể là a Swimmer. Đây là ý nghĩa sâu xa hơn của đa kế thừa: cho phép một đối tượng hoạt động giống như nó thuộc một số lớp khác nhau không liên quan cùng một lúc.


1
Được củng cố bởi tài liệu của Oracle: docs.oracle.com/javase/tutorial/java/IandI/… . Tôi cảm ơn bạn rất nhiều vì đã phân biệt được sự thừa kế của các kiểu và định nghĩa "truyền thống" hơn về sự kế thừa, bao gồm cả việc thực hiện. Tôi đã cố gắng tìm hiểu cách mà các giao diện có thể được coi là một dạng đa kế thừa trong nhiều ngày, và bây giờ thì đã rõ. Java chỉ đơn giản sử dụng một định nghĩa kế thừa khác với tôi mong đợi. Tôi ước tôi có thể cung cấp cho bạn thêm 61 lượt ủng hộ, vì tôi nghĩ đó là câu trả lời mạnh mẽ hơn câu trả lời hiện đang được chấp nhận.
skrrgwasme

17

Đây là một cách để đạt được đa kế thừa thông qua các giao diện trong java.

Đạt được gì?
class A mở rộng B, C // điều này không thể thực hiện được trong java trực tiếp nhưng có thể đạt được gián tiếp.

class B{
   public void getValueB(){}
}

class C{
   public void getValueC(){}
}


interface cInterface{
   public getValueC();
}

class cChild extends C implemets cInterface{
    public getValueC(){

      // implementation goes here, call the super class's getValueC();

    }
}


// Below code is **like** class A extends B, C 
class A extends B implements cInterface{
   cInterface child =  new cChild();
   child.getValueC();
}

Cảm ơn rât nhiều. Đây là câu trả lời cho tôi.
exploredun

1
@challenger Khi bạn triển khai "cInterface", chúng ta sẽ cần triển khai "getValueC ()" trong lớp A phải không?
Nick

10

đưa ra hai giao diện bên dưới ...

interface I1 {
  abstract void test(int i);
}
interface I2 {
  abstract void test(String s);
}

Chúng tôi có thể triển khai cả hai điều này bằng cách sử dụng mã bên dưới ...

public class MultInterfaces implements I1, I2 {
  public void test(int i) {
    System.out.println("In MultInterfaces.I1.test");
  }
  public void test(String s) {
    System.out.println("In MultInterfaces.I2.test");
  }
  public static void main(String[] a) {
    MultInterfaces t = new MultInterfaces();
    t.test(42);
    t.test("Hello");
  }
}

Chúng ta KHÔNG THỂ mở rộng hai đối tượng, nhưng chúng ta có thể triển khai hai giao diện.


Điều gì sẽ xảy ra nếu hai phương thức trong I1 & I2 có cùng loại đối số?
Nivetha T

Sau đó, bạn chỉ có một phương pháp, trình biên dịch sẽ không quan tâm vì chúng làm điều tương tự. Xem câu trả lời tại đây stackoverflow.com/questions/2801878/…
david99world

10

Các giao diện không mô phỏng đa kế thừa. Những người tạo Java đã coi đa kế thừa là sai, vì vậy không có điều đó trong Java.

Nếu bạn muốn kết hợp chức năng của hai lớp thành một - hãy sử dụng thành phần đối tượng. I E

public class Main {
    private Component1 component1 = new Component1();    
    private Component2 component2 = new Component2();
}

Và nếu bạn muốn hiển thị các phương thức nhất định, hãy xác định chúng và để chúng ủy quyền cuộc gọi cho bộ điều khiển tương ứng.

Ở đây các giao diện có thể hữu ích - nếu Component1triển khai giao diện Interface1Component2triển khai Interface2, bạn có thể xác định

class Main implements Interface1, Interface2

Vì vậy, bạn có thể sử dụng các đối tượng thay thế cho nhau khi ngữ cảnh cho phép nó.


5

Nó khá đơn giản. Bạn có thể triển khai nhiều hơn một giao diện trong một kiểu. Vì vậy, ví dụ, bạn có thể có một triển khai của Listđó cũng là một thể hiện của Deque(và Java thì có ... LinkedList).

Bạn chỉ không thể kế thừa các triển khai từ nhiều cha mẹ (tức là mở rộng nhiều lớp). Các khai báo (chữ ký phương thức) không có vấn đề gì.


Vâng, đây là lý do tại sao nó "mô phỏng" đa kế thừa.
Erick Robertson

1
@Erik: nó thực sự thực hiện đa kế thừa, chỉ là không thực hiện đa kế thừa.
Joachim Sauer

@Erick: "Mô phỏng" chỉ là một thuật ngữ hữu ích khi bạn có định kiến ​​về cách MI "nên là" từ một ngôn ngữ khác. Thậm chí sau đó đó là một suy nghĩ phá hoại. Đó là đa kế thừa, chỉ được thực hiện duy nhất.
Mark Peters

Vâng, nó kế thừa các chữ ký nhưng không thực hiện. Nếu bạn không thích thuật ngữ "đa kế thừa mô phỏng", vậy còn "đa thừa kế một phần" thì sao? Nó rõ ràng không giống với đa thừa kế đầy đủ. Đối với tôi, có vẻ như phần quan trọng nhất là nếu bạn nói "A mở rộng B triển khai C", thì bạn có thể có một hàm nhận tham số kiểu C và truyền A cho nó. C là một khai báo kiểu tham số hoàn toàn tốt, ngay cả khi nó không đi kèm với khai báo. Bạn có thể không nhận được đồ chơi nhưng ít nhất bạn nhận được hộp.
Jay

Trên thực tế, tôi sẽ quay lại cái này. Tôi nghĩ sẽ đơn giản và đúng đắn hơn nếu "kế thừa" được giữ nghiêm ngặt để nói về việc thực hiện kế thừa.
Mark Peters

5

Bạn biết không, xuất phát từ quan điểm của một nhà phát triển JavaScript đang cố gắng hiểu chuyện quái gì đang xảy ra với thứ này, tôi muốn chỉ ra một vài điều và ai đó hãy cho tôi biết tôi đang thiếu điều gì ở đây nếu tôi cách đánh dấu.

Các giao diện thực sự đơn giản. Đơn giản một cách ngu ngốc. Chúng thật ngu ngốc, đơn giản đến điên cuồng như mọi người nghĩ ban đầu, đó là lý do tại sao có rất nhiều câu hỏi trùng lặp về chủ đề chính xác này bởi vì một lý do để sử dụng chúng đã không rõ ràng bởi những người cố gắng tạo ra nhiều hơn chúng và ở đó đang bị lạm dụng phổ biến trong mọi cơ sở mã phía máy chủ Java mà tôi đã từng tiếp xúc.

Vì vậy, tại sao bạn muốn sử dụng chúng? Hầu hết thời gian bạn sẽ không. Bạn chắc chắn sẽ không muốn sử dụng chúng mọi lúc như nhiều người vẫn nghĩ. Nhưng trước khi tôi đến khi bạn muốn, hãy nói về những gì chúng KHÔNG.

Các giao diện KHÔNG:

  • theo bất kỳ cách nào là một giải pháp cho bất kỳ loại cơ chế kế thừa nào mà Java thiếu. Chúng không liên quan gì đến thừa kế, chúng chưa bao giờ làm, và không có cách nào mô phỏng bất cứ thứ gì giống như thừa kế.
  • nhất thiết phải là thứ gì đó giúp bạn với những thứ bạn đã viết, cũng như nó giúp người kia viết một thứ gì đó có nghĩa là để nội dung của bạn xen vào.

Chúng thực sự đơn giản như bạn nghĩ về cái nhìn đầu tiên. Mọi người luôn lạm dụng một cách ngu ngốc nên thật khó để hiểu được điểm mấu chốt là gì. Nó chỉ là xác nhận / thử nghiệm. Khi bạn đã viết một cái gì đó phù hợp với một giao diện và hoạt động, việc xóa mã "triển khai" đó sẽ không phá vỡ bất cứ điều gì.

Nhưng nếu bạn đang sử dụng các giao diện đúng cách, bạn sẽ không muốn xóa nó vì có nó ở đó cung cấp cho nhà phát triển tiếp theo một công cụ để viết một lớp truy cập cho một tập hợp cơ sở dữ liệu hoặc dịch vụ web khác mà họ muốn phần còn lại của ứng dụng của bạn tiếp tục. sử dụng vì họ biết lớp của họ sẽ không thành công cho đến khi họ có được giao diện hoàn chỉnh 100% như mong đợi. Tất cả các giao diện làm là xác thực lớp của bạn và xác nhận rằng trên thực tế bạn đã triển khai một giao diện như bạn đã hứa. Chỉ có bấy nhiêu thôi.

Chúng cũng có thể di động. Bằng cách hiển thị các định nghĩa giao diện của bạn, bạn có thể cung cấp cho những người muốn sử dụng mã chưa phơi sáng của bạn một tập hợp các phương pháp để tuân theo để các đối tượng của họ sử dụng nó một cách chính xác. Họ không phải triển khai các giao diện. Họ có thể chỉ cần ghi chúng vào một mẩu giấy ghi chú và kiểm tra lại. Nhưng với giao diện, bạn có nhiều sự đảm bảo sẽ không có gì cố gắng hoạt động cho đến khi nó có một phiên bản giao diện phù hợp được đề cập.

Vì vậy, bất kỳ giao diện nào không có khả năng được triển khai nhiều lần? Hoàn toàn vô dụng. Đa kế thừa? Ngừng vươn tới cầu vồng đó. Java tránh chúng là có lý do ngay từ đầu và các đối tượng tổng hợp / tổng hợp dù sao cũng linh hoạt hơn theo nhiều cách. Điều đó không có nghĩa là các giao diện không thể giúp bạn mô hình hóa theo những cách mà đa kế thừa cho phép nhưng nó thực sự không phải là kế thừa theo bất kỳ hình dạng hoặc hình thức nào và không nên được nhìn nhận như vậy. Nó chỉ đảm bảo rằng mã của bạn sẽ không hoạt động cho đến khi bạn triển khai tất cả các phương pháp mà bạn đã thiết lập.


Kế thừa lớp kết hợp hai khái niệm hơi trực giao: (1) khả năng cho các lớp dẫn xuất sử dụng các thành viên của lớp cơ sở như thể chúng là của riêng chúng; (2) khả năng cho một biến của kiểu lớp cơ sở giữ các tham chiếu đến các đối tượng của bất kỳ kiểu dẫn xuất nào. Khía cạnh số 2 là một phần đủ quan trọng của tính kế thừa mà tôi chắc chắn sẽ gọi nó là "kiểu kế thừa" [đặc biệt vì khía cạnh số 1 là một sự tiện lợi, nhưng khía cạnh số 2 là bắt buộc đối với OOP]. Mục đích cơ bản của giao diện là cho phép mã có tham chiếu đến một thứ được biết là có một số chức năng, sử dụng chức năng đó .
supercat

2 cảm thấy giống như một khía cạnh chính của Java OOP do các ràng buộc về thiết kế ngôn ngữ khác hơn là khía cạnh chính của OOP hoặc kế thừa nói chung. Mặc dù tôi vừa khám phá ra rằng bạn có thể định nghĩa và kế thừa các hằng số từ một giao diện trong Java và tôi sẽ gọi điều đó hơn là kiểu kế thừa.
Erik Reppen

Mối quan hệ "X-is-aY" được xác định bởi kế thừa chỉ định rằng mã có thể chấp nhận tham chiếu đến a Ycũng có thể chấp nhận tham chiếu đến X. Mối quan hệ như vậy sẽ có ích lợi gì nếu không thể thay thế được?
supercat

"Khi bạn đã viết một cái gì đó phù hợp với một giao diện và hoạt động, việc xóa mã" triển khai "đó sẽ không phá vỡ bất cứ điều gì." -> Điều này là sai, điều này đặc biệt rõ ràng khi xử lý các giao diện trống (như trong các giao diện đánh dấu: stackoverflow.com/questions/25850328/marker-interfaces-in-java )
hmijail thương tiếc người

3

Nó không phải là một mô phỏng của đa kế thừa. Trong java, bạn không thể kế thừa từ hai lớp, nhưng nếu bạn triển khai hai giao diện "có vẻ như bạn được thừa kế từ hai lớp khác nhau" vì bạn có thể sử dụng lớp của mình như bất kỳ giao diện nào trong hai giao diện của bạn.

Ví dụ

interface MyFirstInteface{
    void method1();
}
interface MySecondInteface{
    void method2();
}
class MyClass implements MyFirstInteface, MySecondInteface{
    public void method1(){
        //Method 1
    }
    public void method2(){
        //Method 2
    }

    public static void main(String... args){
        MyFirstInterface mfi = new MyClass();
        MySecondInterface msi = new MyClass();
    }
}

Điều này sẽ hoạt động và bạn có thể sử dụng mfi và msi, nó có vẻ giống như một đa kế thừa, nhưng không phải vì bạn không thừa kế bất cứ thứ gì, bạn chỉ viết lại các phương thức công khai được cung cấp bởi các giao diện.


3

Bạn cần phải chính xác:

Java cho phép đa kế thừa giao diện, nhưng chỉ kế thừa duy nhất việc triển khai.

Bạn thực hiện đa kế thừa giao diện trong Java như sau:

public interface Foo
{
    String getX(); 
}

public interface Bar
{
    String getY();
}

public class MultipleInterfaces implements Foo, Bar
{
    private Foo foo;
    private Bar bar;

    public MultipleInterfaces(Foo foo, Bar bar)
    {
        this.foo = foo;
        this.bar = bar;
    }

    public String getX() { return this.foo.getX(); }
    public String getY() { return this.bar.getY(); }
}

3

Nhân tiện, lý do tại sao Java không triển khai đa kế thừa đầy đủ là vì nó tạo ra sự mơ hồ. Giả sử bạn có thể nói "A mở rộng B, C", và sau đó cả B và C đều có một hàm "void f (int)". A kế thừa triển khai nào? Với cách tiếp cận của Java, bạn có thể triển khai bất kỳ số lượng giao diện nào, nhưng các giao diện chỉ khai báo một chữ ký. Vì vậy, nếu hai giao diện bao gồm các hàm có cùng chữ ký, tốt thôi, lớp của bạn phải triển khai một hàm với chữ ký đó. Nếu giao diện bạn thừa kế có các chức năng với các chữ ký khác nhau, thì các chức năng không liên quan gì đến nhau, vì vậy không có vấn đề gì về xung đột.

Tôi không nói đây là cách duy nhất. C ++ thực hiện đa kế thừa thực sự bằng cách thiết lập các quy tắc ưu tiên mà việc triển khai sẽ thắng. Nhưng các tác giả của Java đã quyết định loại bỏ sự mơ hồ. Tôi không biết vì niềm tin triết học rằng điều này tạo ra mã sạch hơn hay vì họ không muốn làm thêm tất cả các công việc.


Hãy sửa tôi nếu tôi sai, nhưng theo hiểu biết của tôi, C ++ cũng loại bỏ khả năng thêm các thành viên ảo vào một lớp cơ sở mà không cần biên dịch lại các lớp con và cũng mất danh tính tham chiếu lớp cơ sở. Nếu B có thành viên ảo Q, X và Y đều kế thừa B và ghi đè riêng Q, và Z kế thừa cả X và Y, việc ép kiểu a & Z thành a & X và sau đó & B sẽ mang lại kết quả khác với kết quả ép kiểu a & Z thành a & Y rồi & B .
supercat

2

Không công bằng khi nói rằng các giao diện 'mô phỏng' đa kế thừa.

Chắc chắn, kiểu của bạn có thể triển khai nhiều giao diện và hoạt động đa hình như nhiều kiểu khác nhau. Tuy nhiên, bạn rõ ràng sẽ không kế thừa hành vi hoặc triển khai theo cách sắp xếp này.

Nhìn chung, hãy nhìn vào thành phần mà bạn nghĩ rằng bạn có thể cần đa kế thừa.

HOẶC Một giải pháp tiềm năng để đạt được một thứ gì đó đa kế thừa là giao diện Mixin - http://csis.pace.edu/~bergin/patterns/multipleinheritance.html . Sử dụng cẩn thận!


2

Họ không.

Tôi nghĩ rằng sự nhầm lẫn đến từ việc mọi người tin rằng việc triển khai một giao diện tạo thành một hình thức kế thừa nào đó. Nó không; việc thực hiện có thể đơn giản là để trống, không có hành vi nào bị buộc bởi hành vi hoặc được đảm bảo thông qua bất kỳ hợp đồng nào. Một ví dụ điển hình là giao diện Clonable, mặc dù ám chỉ đến rất nhiều chức năng tuyệt vời, nhưng lại xác định rất ít nên về cơ bản nó vô dụng và có khả năng nguy hiểm.

Bạn thừa hưởng những gì bằng cách triển khai một giao diện? Bong bóng! Vì vậy, theo ý kiến ​​của tôi, hãy ngừng sử dụng từ giao diện và kế thừa trong cùng một câu. Như Michael Borgwardt đã nói, giao diện không phải là một định nghĩa mà là một khía cạnh.


2

Bạn thực sự có thể "kế thừa" từ nhiều lớp cụ thể nếu chúng tự triển khai các giao diện. innerclassesgiúp bạn đạt được điều đó:

interface IBird {
    public void layEgg();
}

interface IMammal {
    public void giveMilk();
}

class Bird implements IBird{
    public void layEgg() {
        System.out.println("Laying eggs...");
    }
}

class Mammal implements IMammal {
    public void giveMilk() {
        System.out.println("Giving milk...");
    }
}

class Platypus implements IMammal, IBird {

    private class LayingEggAnimal extends Bird {}
    private class GivingMilkAnimal extends Mammal {}

    private LayingEggAnimal layingEggAnimal = new LayingEggAnimal();

    private GivingMilkAnimal givingMilkAnimal = new GivingMilkAnimal();

    @Override
    public void layEgg() {
        layingEggAnimal.layEgg();
    }

    @Override
    public void giveMilk() {
        givingMilkAnimal.giveMilk();
    }

}


2

Tôi muốn chỉ ra điều gì đó khiến tôi khó chịu ở phía sau, đến từ C ++, nơi bạn cũng có thể dễ dàng kế thừa nhiều triển khai.

Có một giao diện "rộng" với nhiều phương thức có nghĩa là bạn sẽ phải triển khai nhiều phương thức trong các lớp cụ thể của mình và bạn không thể chia sẻ chúng dễ dàng giữa các triển khai.

Ví dụ:

interface Herbivore {
    void munch(Vegetable v);
};

interface Carnivore {
    void devour(Prey p);
}

interface AllEater : public Herbivore, Carnivore { };

class Fox implements AllEater {
   ... 
};

class Bear implements AllEater {
   ...
};

Trong ví dụ này, Fox và Bear không thể chia sẻ một triển khai cơ sở chung cho cả phương thức giao diện của nó munchdevour.

Nếu các triển khai cơ sở trông như thế này, chúng tôi có thể muốn sử dụng chúng cho FoxBear:

class ForestHerbivore implements Herbivore
    void munch(Vegetable v) { ... }
};

class ForestCarnivore implements Carnivore
    void devour(Prey p) { ... }
};

Nhưng chúng ta không thể kế thừa cả hai điều này. Các triển khai cơ sở cần phải là các biến thành viên trong lớp và các phương thức được định nghĩa có thể chuyển tiếp đến đó. I E:

class Fox implements AllEater {
    private ForestHerbivore m_herbivore;
    private ForestCarnivore m_carnivore;

    void munch(Vegetable v) { m_herbivore.munch(v); }
    void devour(Prey p) { m_carnivore.devour(p); }
}

Điều này sẽ khó sử dụng nếu các giao diện phát triển (tức là hơn 5-10 phương thức ...)

Một cách tiếp cận tốt hơn là xác định một giao diện như một tập hợp các giao diện:

interface AllEater {
    Herbivore asHerbivore();
    Carnivore asCarnivore();
}

Điều này có nghĩa là FoxBearchỉ phải triển khai hai phương thức này và các giao diện và các lớp cơ sở có thể phát triển độc lập với AllEatergiao diện tổng hợp liên quan đến các lớp thực thi.

Ít khớp theo cách này hơn, nếu nó phù hợp với ứng dụng của bạn.


1

Tôi không nghĩ là họ làm.

Kế thừa cụ thể là một mối quan hệ định hướng triển khai giữa các triển khai. Các giao diện hoàn toàn không cung cấp bất kỳ thông tin triển khai nào mà thay vào đó xác định một kiểu. Để có tính kế thừa, bạn cần phải kế thừa cụ thể một số hành vi hoặc thuộc tính từ một lớp cha.

Tôi tin rằng có một câu hỏi ở đây cụ thể về vai trò của giao diện và đa kế thừa, nhưng tôi không thể tìm thấy nó bây giờ ...


1

Thực sự không có mô phỏng đa kế thừa trong Java.

Đôi khi mọi người sẽ nói rằng bạn có thể mô phỏng đa kế thừa bằng Giao diện vì bạn có thể triển khai nhiều hơn một giao diện cho mỗi lớp và sau đó sử dụng thành phần (thay vì kế thừa) trong lớp của bạn để đạt được các hành vi của nhiều lớp mà bạn đang cố gắng kế thừa đầu tiên là.


1

Nếu nó có ý nghĩa trong mô hình đối tượng của bạn, tất nhiên bạn có thể kế thừa từ một lớp và triển khai 1 hoặc nhiều giao diện.


1

Có những trường hợp đa kế thừa trở nên rất tiện dụng và khó thay thế bằng các giao diện mà không cần viết thêm mã. Ví dụ: có những ứng dụng Android sử dụng các lớp bắt nguồn từ Activity và các lớp khác từ FragmentActivity trong cùng một ứng dụng. Nếu bạn có một tính năng cụ thể muốn chia sẻ trong một lớp chung, trong Java, bạn sẽ phải sao chép mã thay vì để các lớp con của Activity và FragmentActivity dẫn xuất từ ​​cùng một lớp SharedFeature. Và việc triển khai kém các generic trong Java cũng không giúp ích được gì vì việc viết như sau là bất hợp pháp:

public class SharedFeature<T> extends <T extends Activity>

...
...

1

Không có hỗ trợ cho đa kế thừa trong java.

Câu chuyện về việc hỗ trợ đa kế thừa sử dụng giao diện là điều mà các nhà phát triển chúng tôi đã đúc kết ra. Giao diện mang lại sự linh hoạt hơn các lớp cụ thể và chúng tôi có tùy chọn triển khai nhiều giao diện bằng cách sử dụng một lớp. Đây là theo thỏa thuận, chúng tôi đang tuân thủ hai bản thiết kế để tạo một lớp.

Điều này đang cố gắng tiến gần hơn đến đa kế thừa. Những gì chúng tôi làm là triển khai nhiều giao diện, ở đây chúng tôi không mở rộng (kế thừa) bất cứ thứ gì. Lớp thực thi là lớp sẽ thêm các thuộc tính và hành vi. Nó không nhận được việc triển khai miễn phí từ các lớp cha. Tôi chỉ đơn giản nói rằng, không có hỗ trợ cho đa kế thừa trong java.



1

Tôi cũng phải nói rằng Java không hỗ trợ đa kế thừa.

Bạn phải phân biệt ý nghĩa giữa từ khóa extendsimplementstừ khóa trong Java. Nếu chúng ta sử dụng extends, chúng ta thực sự đang kế thừa lớp sau từ khóa đó. Nhưng, để làm cho mọi thứ trở nên đơn giản, chúng ta không thể sử dụng extendsnhiều hơn một lần. Nhưng bạn có thể triển khai nhiều Giao diện như bạn muốn.

Nếu bạn triển khai một giao diện, không có khả năng bạn bỏ lỡ việc triển khai tất cả các phương thức trong mỗi giao diện (Ngoại lệ: triển khai mặc định của các phương thức giao diện được giới thiệu trong Java 8) Vì vậy, bây giờ bạn hoàn toàn nhận thức được những gì đang xảy ra với những thứ mà bạn đã nhúng vào lớp mới của mình.

Thực ra tại sao Java không cho phép đa kế thừa, đa kế thừa làm cho mã hơi phức tạp. Đôi khi, hai phương thức của các lớp cha có thể xung đột do có các chữ ký giống nhau. Nhưng nếu bạn buộc phải thực hiện tất cả các phương pháp theo cách thủ công, bạn sẽ hiểu đầy đủ về những gì đang xảy ra, như tôi đã đề cập ở trên. Nó làm cho mã của bạn dễ hiểu hơn đối với bạn.

Nếu bạn cần thêm thông tin về các giao diện Java, hãy xem bài viết này, http://www.geek-programmer.com/introduction-to-java-interfaces/


1

Giữa hai lớp Java nhiều Kế thừa trực tiếp là không thể. Trong trường hợp này java khuyến nghị Sử dụng để giao diện và khai báo phương thức bên trong giao diện và thực hiện phương thức với lớp Con.

interface ParentOne{
   public String parentOneFunction();
}

interface ParentTwo{
    public String parentTwoFunction();
}

class Child implements ParentOne,ParentTwo{

   @Override
    public String parentOneFunction() {
        return "Parent One Finction";
    }

    @Override
    public String parentTwoFunction() {
        return "Parent Two Function";
    }

    public String childFunction(){
       return  "Child Function";
    }
}
public class MultipleInheritanceClass {
    public static void main(String[] args) {
        Child ch = new Child();
        System.out.println(ch.parentOneFunction());
        System.out.println(ch.parentTwoFunction());
        System.out.println(ch.childFunction());
    }
}
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.