Đa kế thừa Java


168

Trong nỗ lực hiểu đầy đủ cách giải quyết nhiều vấn đề thừa kế của Java, tôi có một câu hỏi kinh điển mà tôi cần làm rõ.

Cho phép nói rằng tôi có lớp học Animalnày có các lớp phụ BirdHorsevà tôi cần phải thực hiện một lớp học Pegasuskéo dài từ BirdHorsekể từ khi Pegasuslà cả một con chim và một con ngựa.

Tôi nghĩ rằng đây là vấn đề kim cương cổ điển. Từ những gì tôi có thể hiểu được cách cổ điển để giải quyết việc này là làm cho Animal, BirdHorsecác lớp giao diện và thực hiện Pegasustừ họ.

Tôi đã tự hỏi nếu có một cách khác để giải quyết vấn đề mà tôi vẫn có thể tạo ra các vật thể cho chim và ngựa. Nếu có một cách để có thể tạo ra động vật cũng sẽ rất tuyệt nhưng không cần thiết.


6
Tôi nghĩ bạn có thể tạo thủ công các lớp và lưu trữ chúng dưới dạng thành viên (thành phần thay vì kế thừa). Với lớp Proxy ( docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html ), đây có thể là một tùy chọn, mặc dù bạn cũng sẽ cần các giao diện.
Gábor Bakos

4
@RAM thì nó không nên mở rộng Bird thay vì có hành vi sẽ cho phép nó bay. : Đã giải quyết được vấn đề
Yogesh

11
Chính xác. Làm thế nào về một giao diện CanFly. :-)
Dừa ngạc nhiên

28
Tôi nghĩ rằng đây là cách tiếp cận sai. Bạn có động vật - Ngựa, Chim. Và bạn có tài sản - Bay, Carnivore. Một con Pegasus không phải là Ngựa. Nó là Ngựa có thể bay. Các thuộc tính nên trong giao diện. Vì vậy public class Pegasus extends Horse implements Flying.
nhện của

12
Tôi hiểu lý do tại sao bạn nghĩ rằng nó sai và không tuân thủ các quy tắc sinh học và đánh giá cao sự quan tâm của bạn nhưng liên quan đến chương trình tôi cần xây dựng mà thực sự phải làm với các ngân hàng thì đây là cách tiếp cận tốt nhất đối với tôi. Vì tôi không muốn đăng các vấn đề thực tế của mình vì điều đó sẽ trái với quy tắc, tôi đã thay đổi ví dụ một chút. Cảm ơn mặc dù ...
Sheli

Câu trả lời:


115

Bạn có thể tạo giao diện cho các lớp động vật (lớp theo nghĩa sinh học), chẳng hạn như public interface Equidaecho ngựa và public interface Avialaecho chim (Tôi không phải là nhà sinh vật học, vì vậy các thuật ngữ có thể sai).

Sau đó, bạn vẫn có thể tạo một

public class Bird implements Avialae {
}

public class Horse implements Equidae {}

và cũng

public class Pegasus implements Avialae, Equidae {}

Thêm từ các ý kiến:

Để giảm mã trùng lặp, bạn có thể tạo một lớp trừu tượng chứa hầu hết mã phổ biến của các động vật bạn muốn thực hiện.

public abstract class AbstractHorse implements Equidae {}

public class Horse extends AbstractHorse {}

public class Pegasus extends AbstractHorse implements Avialae {}

Cập nhật

Tôi muốn thêm một chi tiết. Như Brian nhận xét , đây là điều mà OP đã biết.

Tuy nhiên, tôi muốn nhấn mạnh rằng tôi đề nghị bỏ qua vấn đề "đa kế thừa" với các giao diện và tôi không khuyên bạn nên sử dụng các giao diện đại diện cho một loại cụ thể (như Bird) nhưng nhiều hành vi hơn (những người khác đề cập đến gõ vịt, cũng tốt, nhưng ý tôi là: lớp sinh học của loài chim, Avialae). Tôi cũng không khuyên bạn nên sử dụng tên giao diện bắt đầu bằng chữ 'I', chẳng hạn như IBird, không nói gì về lý do tại sao bạn cần giao diện. Đó là điểm khác biệt của câu hỏi: xây dựng hệ thống phân cấp thừa kế bằng các giao diện, sử dụng các lớp trừu tượng khi hữu ích, triển khai các lớp cụ thể khi cần thiết và sử dụng ủy quyền nếu thích hợp.


9
Mà ... chính xác là những gì OP nói rằng họ biết bạn có thể làm trong Q.
Brian Roach

4
Vì Pegasus đã là Ngựa (bay), tôi nghĩ bạn có thể sử dụng lại nhiều mã hơn nếu mở rộng Ngựa và thực hiện Avialae.
Pablo Lozano

8
Tôi không chắc lắm, tôi chưa thấy một con Pegasus nào. Tuy nhiên, trong trường hợp đó tôi muốn sử dụng một AbstractHorse, nó cũng có thể được sử dụng để xây dựng Zebras hoặc các động vật giống ngựa khác.
Moritz Petersen

5
@MoritzPeteren Nếu bạn thực sự muốn sử dụng lại trừu tượng và đặt tên có ý nghĩa, có lẽ AbstractEquidaesẽ phù hợp hơn AbstractHorse. Sẽ thật kỳ lạ khi có một con ngựa vằn kéo dài một con ngựa trừu tượng. Nhân tiện, câu trả lời hay.
afsantos

3
Việc thực hiện gõ vịt cũng sẽ liên quan đến một Ducklớp thực hiện Avialae?
mgarciaisaia

88

Có hai cách tiếp cận cơ bản để kết hợp các đối tượng lại với nhau:

  • Đầu tiên là Kế thừa . Như bạn đã xác định các giới hạn của thừa kế có nghĩa là bạn không thể làm những gì bạn cần ở đây.
  • Thứ hai là Thành phần . Vì kế thừa đã thất bại, bạn cần sử dụng thành phần.

Cách thức hoạt động này là bạn có một đối tượng Động vật. Trong đối tượng đó, sau đó bạn thêm các đối tượng cung cấp các thuộc tính và hành vi mà bạn yêu cầu.

Ví dụ:

  • Chim mở rộng động vật thực hiện sớm hơn
  • Ngựa kéo dài Động vật thực hiện IHerbivore, IQuadruped
  • Pegasus mở rộng Động vật thực hiện IHerbivore, IQuadruped, IF trước đó

Bây giờ IFliertrông giống như thế này:

 interface IFlier {
     Flier getFlier();
 }

Vì vậy, Birdtrông như thế này:

 class Bird extends Animal implements IFlier {
      Flier flier = new Flier();
      public Flier getFlier() { return flier; }
 }

Bây giờ bạn có tất cả những lợi thế của Kế thừa. Bạn có thể sử dụng lại mã. Bạn có thể có một bộ sưu tập IFliers và có thể sử dụng tất cả các lợi thế khác của đa hình, v.v.

Tuy nhiên, bạn cũng có tất cả sự linh hoạt từ Thành phần. Bạn có thể áp dụng bao nhiêu giao diện khác nhau và lớp sao lưu tổng hợp tùy thích cho từng loại Animal- với nhiều quyền kiểm soát như bạn cần đối với cách mỗi bit được thiết lập.

Mô hình chiến lược tiếp cận thay thế thành phần

Một cách tiếp cận khác tùy thuộc vào những gì và cách bạn đang làm là để Animallớp cơ sở chứa một bộ sưu tập nội bộ để giữ danh sách các hành vi khác nhau. Trong trường hợp đó, bạn kết thúc bằng cách sử dụng một cái gì đó gần hơn với Mẫu chiến lược. Điều đó mang lại lợi thế về mặt đơn giản hóa mã (ví dụ: Horsekhông cần biết gì về Quadrupedhoặc Herbivore) nhưng nếu bạn không thực hiện phương pháp giao diện, bạn sẽ mất rất nhiều lợi thế của đa hình, v.v.


Một cách khác tương tự cũng có thể là sử dụng các lớp kiểu, mặc dù chúng không được sử dụng trong Java (bạn phải sử dụng các phương thức chuyển đổi, v.v.), phần giới thiệu này có thể hữu ích để lấy ý tưởng: typeclassopedia.bitbucket.org
Gábor Bakos

1
Đây là một giải pháp tốt hơn nhiều sau đó là cách tiếp cận được đề xuất trong câu trả lời được chấp nhận. Ví dụ: nếu sau này tôi muốn thêm "màu mỏ" vào giao diện Bird, tôi đã gặp sự cố. Pegasus là một hỗn hợp, lấy các yếu tố từ ngựa và chim nhưng không phải ngựa hay chim. Sử dụng thành phần làm cho ý nghĩa hoàn hảo trong kịch bản này.
JDB vẫn còn nhớ Monica

Nhưng getFlier()phải được thực hiện lại cho mỗi loại chim.
SMUsamaShah

1
@ LifeH2O Chia chúng thành các khối chức năng được chia sẻ sau đó cung cấp cho chúng. tức là bạn có thể có MathsTeacherEnglishTeachercả kế thừa Teacher, ChemicalEngineer, MaterialsEngineervv kế thừa Engineer. TeacherEngineercả hai thực hiện Component. Sau Personđó chỉ có một danh sách các Components, và bạn có thể cung cấp cho họ các Components phù hợp cho điều đó Person. tức là person.getComponent(Teacher.class), person.getComponent(MathsTeacher.class)v.v.
Tim B

1
Đây là câu trả lời tốt nhất. Theo nguyên tắc thông thường, tính kế thừa đại diện cho "là" và giao diện đại diện cho "có thể". Một con Pegasus là một động vật có thể bay và đi bộ. Một con chim là một động vật có thể bay. Ngựa là một động vật có thể đi bộ.
Robear

43

Tôi có một ý tưởng ngu ngốc:

public class Pegasus {
    private Horse horseFeatures; 
    private Bird birdFeatures; 

   public Pegasus(Horse horse, Bird bird) {
     this.horseFeatures = horse;
     this.birdFeatures = bird;
   }

  public void jump() {
    horseFeatures.jump();
  }

  public void fly() {
    birdFeatures.fly();
  }
}

24
Nó sẽ hoạt động, nhưng tôi không thích cách tiếp cận đó (Wrappper) bởi vì sau đó có vẻ như Pegasus ĐÃ có một con ngựa, thay vào đó là một con ngựa.
Pablo Lozano

Cảm ơn bạn. Tôi không thể giúp mình đăng ý tưởng. Tôi biết điều đó thật ngu ngốc, nhưng tôi không thấy TẠI SAO nó ngu ngốc ...
Pavel Janicek 17/214

3
Nó gần giống như một phiên bản chưa được giới thiệu của phương pháp sáng tác từ câu trả lời của Tim B.
Stephan

1
Đây ít nhiều là cách được chấp nhận để làm điều đó, mặc dù bạn cũng nên có một cái gì đó giống như IJumps với phương pháp "nhảy" được thực hiện bởi Horse và Pegasus và IFlies bằng phương pháp "bay" được thực hiện bởi Bird và Pegasus.
MatsT

2
@Pablo không, một con ngựa đã có tính năng con ngựa và tính năng con chim. +1 cho câu trả lời vì nó giữ cho mã đơn giản, không giống như các giải pháp Java phù hợp, sinh sản theo lớp, phù hợp.
Jane Goodall

25

Tôi có thể đề xuất khái niệm gõ vịt không?

Nhiều khả năng bạn sẽ có xu hướng làm cho Pegasus mở rộng giao diện Bird and Horse nhưng gõ vịt thực sự gợi ý rằng bạn nên kế thừa hành vi . Như đã nêu trong các ý kiến, một con chó đốm không phải là một con chim nhưng nó có thể bay. Vì vậy, Pegasus của bạn nên kế thừa một Flyablegiao diện và cho phép nóiGallopable giao diện.

Loại khái niệm này được sử dụng trong Mô hình chiến lược . Ví dụ đưa ra thực sự cho bạn thấy làm thế nào một kế thừa vịt FlyBehaviourQuackBehaviourvà vẫn có thể có con vịt, ví dụ như RubberDuck, mà không thể bay. Họ cũng có thể tạo ra Duckmột Birdlớp mở rộng nhưng sau đó họ sẽ từ bỏ một số linh hoạt, bởi vì mọi người đều Duckcó thể bay, ngay cả những người nghèo RubberDuck.


19

Về mặt kỹ thuật, bạn chỉ có thể mở rộng một lớp cùng một lúc và thực hiện nhiều giao diện, nhưng khi đặt tay vào công nghệ phần mềm, tôi muốn đề xuất một giải pháp cụ thể cho vấn đề không thể trả lời được. Nhân tiện, đó là cách thực hành OO tốt, không mở rộng các lớp cụ thể / chỉ mở rộng các lớp trừu tượng để ngăn chặn hành vi thừa kế không mong muốn - không có thứ gọi là "động vật" và không sử dụng vật thể động vật mà chỉ sử dụng động vật cụ thể.


13

Trong Java 8, vẫn đang trong giai đoạn phát triển kể từ tháng 2 năm 2014, bạn có thể sử dụng các phương thức mặc định để đạt được một loại C ++ - giống như nhiều kế thừa. Bạn cũng có thể xem hướng dẫn này trong đó cho thấy một vài ví dụ sẽ dễ bắt đầu làm việc hơn tài liệu chính thức.


1
Mặc dù vậy, hãy lưu ý rằng nếu cả Bird và Horse của bạn đều có phương thức mặc định, bạn vẫn sẽ gặp phải sự cố kim cương và sẽ phải triển khai riêng trong lớp Pegasus của bạn (hoặc gặp lỗi trình biên dịch).
Mikkel Løkke

@Mikkel Løkke: Lớp Pegasus phải xác định ghi đè cho các phương thức mơ hồ nhưng có thể thực hiện chúng bằng cách chỉ ủy thác cho một siêu phương thức (hoặc cả hai theo thứ tự đã chọn).
Holger

12

Giữ ngựa ở trong chuồng có một nửa cửa là an toàn, vì ngựa không thể vượt qua nửa cửa. Do đó, tôi thiết lập một dịch vụ chuồng ngựa chấp nhận bất kỳ vật phẩm nào thuộc loại ngựa và đặt nó trong chuồng có một nửa cửa.

Vì vậy, một con ngựa giống như động vật có thể bay ngay cả một con ngựa?

Tôi đã từng nghĩ rất nhiều về việc thừa kế nhiều lần, tuy nhiên bây giờ tôi đã lập trình được hơn 15 năm, tôi không còn quan tâm đến việc thực hiện nhiều kế thừa.

Thường xuyên hơn không, khi tôi đã cố gắng đối phó với một thiết kế hướng đến nhiều sự kế thừa, sau đó tôi đã đến để phát hành rằng tôi đã bỏ lỡ hiểu miền vấn đề.

HOẶC LÀ

Nếu nó trông giống như một con vịt và quạ giống như một con vịt nhưng nó cần pin, có lẽ bạn đã trừu tượng sai .


Nếu tôi đọc chính xác sự tương tự của bạn, bạn đang nói rằng trong các giao diện ban đầu có vẻ rất tuyệt, vì chúng cho phép bạn giải quyết các vấn đề về thiết kế, ví dụ bạn có thể sử dụng API của người khác bằng cách buộc các lớp của bạn thông qua giao diện của họ. Nhưng sau một vài năm, bạn nhận ra rằng vấn đề là thiết kế tồi để bắt đầu.
CS

8

Java không có vấn đề Đa kế thừa, vì nó không có nhiều kế thừa. Điều này là do thiết kế, để giải quyết vấn đề thừa kế thực sự (Vấn đề kim cương).

Có nhiều chiến lược khác nhau để giảm thiểu vấn đề. Đối tượng có thể đạt được ngay lập tức nhất là đối tượng Tổng hợp mà Pavel gợi ý (về cơ bản là cách C ++ xử lý nó). Tôi không biết nếu nhiều kế thừa thông qua tuyến tính hóa C3 (hoặc tương tự) có trên các thẻ cho tương lai của Java hay không, nhưng tôi nghi ngờ điều đó.

Nếu câu hỏi của bạn mang tính học thuật, thì giải pháp chính xác là Chim và Ngựa cụ thể hơn, và thật sai lầm khi cho rằng một con Pegasus chỉ đơn giản là một con Chim và Ngựa kết hợp. Sẽ đúng hơn khi nói rằng một con Pegasus có những đặc tính nội tại nhất định chung với Chim và Ngựa (nghĩa là chúng có thể có tổ tiên chung). Điều này có thể được mô hình đầy đủ như câu trả lời của Moritz chỉ ra.


6

Tôi nghĩ rằng nó phụ thuộc rất nhiều vào nhu cầu của bạn và cách các lớp động vật của bạn được sử dụng trong mã của bạn.

Nếu bạn muốn có thể sử dụng các phương thức và tính năng của việc triển khai Ngựa và Chim trong lớp Pegasus của mình, thì bạn có thể triển khai Pegasus như một thành phần của Chim và Ngựa:

public class Animals {

    public interface Animal{
        public int getNumberOfLegs();
        public boolean canFly();
        public boolean canBeRidden();
    }

    public interface Bird extends Animal{
        public void doSomeBirdThing();
    }
    public interface Horse extends Animal{
        public void doSomeHorseThing();
    }
    public interface Pegasus extends Bird,Horse{

    }

    public abstract class AnimalImpl implements Animal{
        private final int numberOfLegs;

        public AnimalImpl(int numberOfLegs) {
            super();
            this.numberOfLegs = numberOfLegs;
        }

        @Override
        public int getNumberOfLegs() {
            return numberOfLegs;
        }
    }

    public class BirdImpl extends AnimalImpl implements Bird{

        public BirdImpl() {
            super(2);
        }

        @Override
        public boolean canFly() {
            return true;
        }

        @Override
        public boolean canBeRidden() {
            return false;
        }

        @Override
        public void doSomeBirdThing() {
            System.out.println("doing some bird thing...");
        }

    }

    public class HorseImpl extends AnimalImpl implements Horse{

        public HorseImpl() {
            super(4);
        }

        @Override
        public boolean canFly() {
            return false;
        }

        @Override
        public boolean canBeRidden() {
            return true;
        }

        @Override
        public void doSomeHorseThing() {
            System.out.println("doing some horse thing...");
        }

    }

    public class PegasusImpl implements Pegasus{

        private final Horse horse = new HorseImpl();
        private final Bird bird = new BirdImpl();


        @Override
        public void doSomeBirdThing() {
            bird.doSomeBirdThing();
        }

        @Override
        public int getNumberOfLegs() {
            return horse.getNumberOfLegs();
        }

        @Override
        public void doSomeHorseThing() {
            horse.doSomeHorseThing();
        }


        @Override
        public boolean canFly() {
            return true;
        }

        @Override
        public boolean canBeRidden() {
            return true;
        }
    }
}

Một khả năng khác là sử dụng một Thực thể-Thành phần-Hệ thống cách tiếp cận thay vì kế thừa để xác định động vật của bạn. Tất nhiên điều này có nghĩa là, bạn sẽ không có các lớp động vật Java riêng lẻ, mà thay vào đó chúng chỉ được xác định bởi các thành phần của chúng.

Một số mã giả cho cách tiếp cận Thực thể-Thành phần-Hệ thống có thể trông như thế này:

public void createHorse(Entity entity){
    entity.setComponent(NUMER_OF_LEGS, 4);
    entity.setComponent(CAN_FLY, false);
    entity.setComponent(CAN_BE_RIDDEN, true);
    entity.setComponent(SOME_HORSE_FUNCTIONALITY, new HorseFunction());
}

public void createBird(Entity entity){
    entity.setComponent(NUMER_OF_LEGS, 2);
    entity.setComponent(CAN_FLY, true);
    entity.setComponent(CAN_BE_RIDDEN, false);
    entity.setComponent(SOME_BIRD_FUNCTIONALITY, new BirdFunction());
}

public void createPegasus(Entity entity){
    createHorse(entity);
    createBird(entity);
    entity.setComponent(CAN_BE_RIDDEN, true);
}

4

bạn có thể có một hệ thống phân cấp giao diện và sau đó mở rộng các lớp của bạn từ các giao diện được chọn:

public interface IAnimal {
}

public interface IBird implements IAnimal {
}

public  interface IHorse implements IAnimal {
}

public interface IPegasus implements IBird,IHorse{
}

và sau đó xác định các lớp của bạn khi cần, bằng cách mở rộng một giao diện cụ thể:

public class Bird implements IBird {
}

public class Horse implements IHorse{
}

public class Pegasus implements IPegasus {
}

1
Hoặc anh ta chỉ có thể: Lớp học công cộng Pegasus mở rộng Ngựa thực hiện Động vật, Chim
dơi

OP đã nhận thức được giải pháp này, anh ấy đang tìm cách thay thế để thực hiện
Yogesh

@Batman, tất nhiên anh ta có thể nhưng nếu anh ta muốn mở rộng hệ thống phân cấp, anh ta sẽ cần phải làm theo phương pháp này
richardtz

IBirdIHorsenên thực hiện IAnimalthay vìAnimal
oliholz

@Yogesh, bạn nói đúng. Tôi bỏ qua nơi anh nói nó. Là một "người mới" tôi nên làm gì bây giờ, xóa câu trả lời hoặc để nó ở đó?, Cảm ơn.
richardtz

4

Ehm, lớp của bạn có thể là lớp con chỉ cho 1 người khác, nhưng vẫn có thể có nhiều giao diện được triển khai như bạn muốn.

Một con Pegasus trên thực tế là một con ngựa (đó là trường hợp đặc biệt của một con ngựa), có khả năng bay (đó là "kỹ năng" của con ngựa đặc biệt này). Mặt khác, bạn có thể nói, Pegasus là một con chim, có thể đi bộ và được 4 con - tất cả phụ thuộc vào việc bạn viết mã dễ dàng hơn như thế nào.

Giống như trong trường hợp của bạn, bạn có thể nói:

abstract class Animal {
   private Integer hp = 0; 
   public void eat() { 
      hp++; 
   }
}
interface AirCompatible { 
   public void fly(); 
}
class Bird extends Animal implements AirCompatible { 
   @Override
   public void fly() {  
       //Do something useful
   }
} 
class Horse extends Animal {
   @Override
   public void eat() { 
      hp+=2; 
   }

}
class Pegasus extends Horse implements AirCompatible {
   //now every time when your Pegasus eats, will receive +2 hp  
   @Override
   public void fly() {  
       //Do something useful
   }
}

3

Các giao diện không mô phỏng nhiều kế thừa. Những người tạo Java đã coi nhiều 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 - 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 đưa ra một số 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ể có ích - nếu Component1thực hiện giao diện Interface1Component2thực hiện 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 trong bối cảnh cho phép nó.

Vì vậy, theo quan điểm của tôi, bạn không thể gặp vấn đề về kim cương.


Nó không sai theo cùng một cách mà các con trỏ bộ nhớ trực tiếp, các kiểu không dấu và quá tải toán tử không sai; nó không cần thiết để hoàn thành công việc Java được thiết kế như một ngôn ngữ nạc dễ lấy. Đừng tạo ra thứ gì đó và hy vọng điều tốt nhất, đây là một lĩnh vực kiến ​​thức, không phải là phỏng đoán.
Gimby


3
  1. Xác định giao diện để xác định các khả năng. Bạn có thể xác định nhiều giao diện cho nhiều khả năng. Những khả năng này có thể được thực hiện bởi Động vật hoặc Chim cụ thể .
  2. Sử dụng thừa kế để thiết lập mối quan hệ giữa các lớp bằng cách chia sẻ dữ liệu / phương thức không tĩnh và không công khai.
  3. Sử dụng Decorator_potype để thêm các khả năng một cách linh hoạt. Điều này sẽ cho phép bạn giảm số lượng các lớp & kết hợp thừa kế.

Hãy xem ví dụ dưới đây để hiểu rõ hơn

Khi nào nên sử dụng mẫu trang trí?


2

Để giảm độ phức tạp và đơn giản hóa ngôn ngữ, nhiều kế thừa không được hỗ trợ trong java.

Hãy xem xét một kịch bản trong đó A, B và C là ba lớp. Lớp C kế thừa các lớp A và B. Nếu các lớp A và B 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ồ để gọi phương thức của lớp A hoặc B.

Vì lỗi thời gian biên dịch tốt hơn lỗi thời gian chạy, java biểu hiện lỗi thời gian biên dịch nếu bạn kế thừa 2 lớp. Vì vậy, cho dù bạn có cùng phương thức hay khác nhau, sẽ có lỗi thời gian biên dịch ngay bây giờ.

class A {  
    void msg() {
        System.out.println("From A");
    }  
}

class B {  
    void msg() {
        System.out.println("From B");
    }  
}

class C extends A,B { // suppose if this was possible
    public static void main(String[] args) {  
        C obj = new C();  
        obj.msg(); // which msg() method would be invoked?  
    }
} 

2

Để giải quyết vấn đề thừa kế đa dạng trong Java → giao diện được sử dụng

Ghi chú J2EE (lõi JAVA) của ông KVR Trang 51

Ngày - 27

  1. Các giao diện về cơ bản được sử dụng để phát triển các kiểu dữ liệu do người dùng xác định.
  2. Đối với các giao diện, chúng ta có thể đạt được khái niệm về nhiều kế thừa.
  3. Với các giao diện, chúng ta có thể đạt được khái niệm về đa hình, liên kết động và do đó chúng ta có thể cải thiện hiệu suất của chương trình JAVA theo lượt không gian bộ nhớ và thời gian thực hiện.

Giao diện là một cấu trúc chứa tập hợp các phương thức hoàn toàn không xác định hoặc giao diện là tập hợp các phương thức hoàn toàn trừu tượng.

[...]

Ngày - 28:

Cú pháp-1 để sử dụng lại các tính năng của (các) giao diện cho lớp:

[abstract] class <clsname> implements <intf 1>,<intf 2>.........<intf n>
{
    variable declaration;
    method definition or declaration;
};

Trong cú pháp trên, clsname đại diện cho tên của lớp đang kế thừa các tính năng từ số lượng giao diện. 'Implements' là một từ khóa được sử dụng để kế thừa các tính năng của (các) giao diện cho một lớp dẫn xuất.

[...]

Cú pháp-2 kế thừa số lượng giao diện 'n' sang giao diện khác:

interface <intf 0 name> extends <intf 1>,<intf 2>.........<intf n>
{     
    variable declaration cum initialization;
    method declaration;
};

[...]

Cú pháp-3:

[abstract] class <derived class name> extends <base class name> implements <intf 1>,<intf 2>.........<intf n>
{
  variable declaration;
  method definition or declaration;
};
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.