Sự khác biệt chính giữa Kế thừa và Đa hình là gì?


172

Tôi đã được trình bày với câu hỏi này trong phần cuối của kỳ thi mở sách mô-đun ngày hôm nay và thấy mình bị lạc. Tôi đã đọc Head first Javavà cả hai định nghĩa dường như giống hệt nhau. Tôi chỉ tự hỏi sự khác biệt CHÍNH là gì đối với suy nghĩ của riêng tôi. Tôi biết có một số câu hỏi tương tự như vậy nhưng, không có câu hỏi nào tôi thấy câu trả lời dứt khoát.


2
Bằng cách nào đó liên quan đến câu hỏi này: Có thể đa hình mà không cần thừa kế
Edwin Dalorzo

Câu trả lời:


289

Kế thừa là khi một 'lớp' xuất phát từ một 'lớp' hiện có. Vì vậy, nếu bạn có một Personlớp, thì bạn có một Studentlớp mở rộng Person, Student kế thừa tất cả những thứ Personcó. Có một số chi tiết xung quanh các công cụ sửa đổi truy cập mà bạn đưa vào các trường / phương thức trong Person, nhưng đó là ý tưởng cơ bản. Ví dụ: nếu bạn có trường riêng trên Person, Studentsẽ không thấy trường đó vì trường riêng và trường riêng không hiển thị cho các lớp con.

Đa hình liên quan đến cách chương trình quyết định nên sử dụng phương pháp nào, tùy thuộc vào loại điều mà nó có. Nếu bạn có một phương thức, Personcó một readphương thức và bạn có một phương thức Studentmở rộng Person, có triển khai riêng read, phương thức nào được gọi được xác định cho bạn bởi thời gian chạy, tùy thuộc vào việc bạn có một Personhoặc a Student. Nó có một chút khó khăn, nhưng nếu bạn làm một cái gì đó như

Person p = new Student();
p.read();

phương pháp đọc trên Học sinh được gọi. Đó là sự đa hình trong hành động. Bạn có thể thực hiện nhiệm vụ đó vì a Student là a Person , nhưng thời gian chạy đủ thông minh để biết rằng loại thực tế pSinh viên .

Lưu ý rằng chi tiết khác nhau giữa các ngôn ngữ. Bạn có thể thực hiện kế thừa trong javascript, nhưng nó hoàn toàn khác so với cách nó hoạt động trong Java.


9
@ hvgtcodes vì ​​vậy, trong một tóm tắt, mối quan hệ lớp siêu lớp là sự kế thừa và khái niệm thực hiện cùng một phương thức theo một cách khác nhau giữa lớp cha và lớp con của nó và gọi chúng dựa trên tình huống là Đa hình ,. Tôi có đúng không?
Muhammad Raihan Muhaimin

1
@hvgotcodes nhưng nói nếu Person's readphương pháp được sử dụng sửa đổi lần truy cập công cộng, sẽ không Studentđối tượng có thể truy cập chúng? và sau đó Student s = new Student();sẽ không dễ dàng hơn? Tôi vẫn chưa thực sự nhận được những lợi ích của Polymporphism.
Scorpiorian83

1
@hvgotcodes Sinh viên s = new Student () sẽ hoạt động. Nhưng hãy nói sau khi bạn viết rất nhiều mã sử dụng ý tưởng này và sau đó bạn nhận ra rằng mình đã phạm sai lầm. Người thực sự không phải là một học sinh, nó là một giáo viên. Vì vậy, bạn có thể chỉ cần thay đổi từ Person p = new Student () thành Person p = new teacher (), sau đó nó sẽ làm cho cuộc sống của bạn đơn giản hơn rất nhiều.
munmunbb

Câu hỏi của tôi ở đây là tại sao bạn muốn sử dụng Person p = new Student();thay vì Student p = new Student();?
PerfectContrast

@PerinfContrast Tôi nghĩ rằng nó hữu ích khi bạn muốn có học sinh, tài xế, giáo viên, v.v. làm Người và bạn nhóm chúng theo Danh sách hoặc thứ gì đó. Vì vậy, khi bạn gọi 'đọc' cho tất cả, mọi người đều gọi phương thức 'đọc' của riêng họ.
savante

205

Kế thừa đề cập đến việc sử dụng cấu trúc và hành vi của một siêu lớp trong một lớp con.

Đa hình đề cập đến việc thay đổi hành vi của một siêu lớp trong lớp con.


5
Có câu trả lời này ngụ ý rằng đa hình đòi hỏi sự kế thừa?
jaco0646

6
@ jaco0646 - Trong bối cảnh của Java, tôi nghĩ vậy. (Trong các ngôn ngữ khác, có lẽ không quá nhiều.) Lưu ý rằng "siêu lớp" và "lớp con" được sử dụng một cách lỏng lẻo ở đây. Đa hình cũng có thể có nghĩa là kế thừa hành vi được chỉ định (nhưng không được thực hiện) trong một giao diện.
Ted Hopp

1
@AlirezaRahmani - Tôi không hiểu bình luận của bạn. Bạn có nghĩa là thừa kế không liên quan đến việc kế thừa cả tài sản và hành vi? Điều đó sẽ trái với cách Java (và hầu hết các ngôn ngữ hướng đối tượng, dựa trên lớp) định nghĩa kế thừa. Từ Đặc tả ngôn ngữ Java, §8.4.8 : "Một lớp C kế thừa từ siêu lớp trực tiếp của nó tất cả các phương thức cụ thể m(cả staticinstance) của siêu lớp mà ..." (tiếp theo là chi tiết về kế thừa). Âm thanh như "tái sử dụng mã" với tôi.
Ted Hopp

@TedHopp Kế thừa chủ yếu là một công cụ đa hình, nhưng một số người, trong tình trạng nguy hiểm sau này, cố gắng sử dụng nó như một cách để sử dụng lại / chia sẻ mã. Lý do là "tốt nếu tôi thừa kế thì tôi nhận được tất cả các phương thức miễn phí", nhưng bỏ qua thực tế là hai lớp này có khả năng không có mối quan hệ đa hình.
Alireza Rahmani Khalili

1
@AlirezaRahmani - Trong Java (đó là những gì OP đặc biệt hỏi về, theo các thẻ), kế thừa lớp chắc chắn liên quan đến kế thừa hành vi. Đó là một phần của định nghĩa ngôn ngữ. Thực tế là điều này có thể bị sử dụng sai như bạn mô tả là một trong những điểm yếu của Java. (Một điểm yếu liên quan liên quan đến việc khai báo các lớp để thực hiện các giao diện chỉ đơn giản là nhập các hằng số được xác định trong giao diện. Cuối cùng, các nhà thiết kế Java đã giới thiệu import staticđể loại bỏ việc sử dụng sai giao diện này.)
Ted Hopp

63

Đa hình : Khả năng xử lý các đối tượng thuộc các loại khác nhau theo cách tương tự. Ví dụ: Hươu cao cổ và Cá sấu đều là Động vật và động vật có thể Move. Nếu bạn có một ví dụ về một Animalthì bạn có thể gọi Movemà không cần biết hoặc quan tâm nó là loại động vật nào.

Kế thừa : Đây là một cách để đạt được cả Đa hình và tái sử dụng mã cùng một lúc.

Các dạng đa hình khác : Có nhiều cách khác để đạt được đa hình, chẳng hạn như giao diện, chỉ cung cấp đa hình nhưng không sử dụng lại mã (đôi khi mã này khá khác nhau, chẳng hạn như Moveđối với Snake sẽ khác hoàn toàn vớiMove với Chó, trong trường hợp đó một Giao diện sẽ là sự lựa chọn đa hình tốt hơn trong trường hợp này.

Trong các ngôn ngữ động khác, tính đa hình có thể đạt được với Duck Typing, đó là các lớp thậm chí không cần chia sẻ cùng một lớp cơ sở hoặc giao diện, chúng chỉ cần một phương thức có cùng tên. Hoặc thậm chí năng động hơn như Javascript, bạn thậm chí không cần các lớp, chỉ một đối tượng có cùng tên phương thức có thể được sử dụng đa hình.


17

Sự khác biệt chính là đa hình là kết quả cụ thể của thừa kế. Đa hình là nơi mà phương thức được gọi được xác định trong thời gian chạy dựa trên loại đối tượng. Đây là một tình huống xảy ra khi bạn có một lớp kế thừa từ một lớp khác và ghi đè một phương thức cụ thể. Tuy nhiên, trong cây thừa kế bình thường, bạn không phải ghi đè bất kỳ phương thức nào và do đó, không phải tất cả các lệnh gọi phương thức đều phải đa hình. Điều đó có ý nghĩa? Đây là một vấn đề tương tự với tất cả các xe Ford là ô tô, nhưng không phải tất cả ô tô đều là Fords (mặc dù không hoàn toàn ....).

Ngoài ra, tính đa hình liên quan đến việc gọi phương thức trong khi kế thừa cũng mô tả các thành viên dữ liệu, v.v.


12

Trong Java, hai cái này có liên quan chặt chẽ với nhau. Điều này là do Java sử dụng một kỹ thuật để gọi phương thức gọi là "công văn động". Nếu tôi có

public class A {
  public void draw() { ... }
  public void spin() { ... }
}

public class B extends A {
  public void draw() { ... }
  public void bad() { ... }
}

...

A testObject = new B();

testObject.draw(); // calls B's draw, polymorphic
testObject.spin(); // calls A's spin, inherited by B
testObject.bad(); // compiler error, you are manipulating this as an A

Sau đó, chúng ta thấy rằng kế thừa B spintừ A. Tuy nhiên, khi chúng tôi cố gắng để thao tác các đối tượng như thể nó là một loại A, chúng tôi vẫn nhận được hành vi của B cho draw. Cácdraw hành vi là đa hình.

Trong một số ngôn ngữ, tính đa hình và tính kế thừa không liên quan chặt chẽ với nhau. Ví dụ, trong C ++, các hàm không được khai báo ảo được kế thừa, nhưng sẽ không được gửi đi một cách linh hoạt, do đó bạn sẽ không có hành vi đa hình đó ngay cả khi bạn sử dụng tính kế thừa.

Trong javascript, mọi lệnh gọi hàm được gửi tự động và bạn có kiểu gõ yếu. Điều này có nghĩa là bạn có thể có một loạt các đối tượng không liên quan, mỗi đối tượng của riêng chúng draw, có một chức năng lặp lại chúng và gọi hàm đó, và mỗi đối tượng sẽ hoạt động tốt. Bạn sẽ có bản vẽ đa hình của riêng mình mà không cần kế thừa.


12

Đa hình: Giả sử bạn làm việc cho một công ty bán bút. Vì vậy, bạn tạo ra một lớp rất đẹp gọi là "Bút" xử lý mọi thứ bạn cần biết về bút. Bạn viết tất cả các loại lớp để thanh toán, vận chuyển, tạo hóa đơn, tất cả đều sử dụng lớp Pen. Một ông chủ ngày đến và nói, "Tin tuyệt vời! Công ty đang phát triển và chúng tôi đang bán Sách & CD ngay bây giờ!" Không phải tin tuyệt vời vì bây giờ bạn phải thay đổi mọi lớp sử dụng Bút cũng sử dụng Sách & CD. Nhưng điều gì sẽ xảy ra nếu ban đầu bạn đã tạo ra một giao diện gọi là "SellableSản phẩm" và Pen đã triển khai giao diện này. Sau đó, bạn có thể đã viết tất cả các lớp vận chuyển, lập hóa đơn, vv để sử dụng giao diện đó thay vì Bút. Bây giờ, tất cả những gì bạn cần làm là tạo một lớp mới gọi là Book & CompactDisc, thực hiện giao diện Sellable Productt. Vì tính đa hình, tất cả các lớp khác có thể tiếp tục hoạt động mà không thay đổi! Có lý?

Vì vậy, nó có nghĩa là sử dụng Kế thừa là một trong những cách để đạt được đa hình.

Polymorhism có thể có thể trong một lớp / giao diện nhưng Kế thừa luôn nằm giữa 2 HOẶC nhiều lớp / giao diện hơn. Kế thừa luôn tuân thủ mối quan hệ "is-a" trong khi không phải lúc nào cũng có tính đa hình (có thể tuân thủ cả mối quan hệ "is-a" / "has-a".


6

Kế thừa là một thứ tĩnh hơn (một lớp mở rộng một lớp khác) trong khi đa hình là một thứ động / thời gian chạy (một đối tượng hành xử theo kiểu động / thời gian chạy của nó không theo kiểu tĩnh / khai báo của nó).

Ví dụ

// This assignment is possible because B extends A
A a = new B();
// polymorphic call/ access
a.foo();

-> Mặc dù kiểu tĩnh / khai báo của a là A, nhưng kiểu động / thời gian chạy thực tế là B và do đó a.foo () sẽ thực thi foo như được định nghĩa trong B không thuộc A.


3

Đa hình là một cách tiếp cận để thể hiện hành vi phổ biến giữa các loại đối tượng có đặc điểm tương tự nhau. Nó cũng cho phép các biến thể của những đặc điểm đó được tạo ra thông qua ghi đè. Kế thừa là một cách để đạt được tính đa hình thông qua hệ thống phân cấp đối tượng nơi các đối tượng thể hiện mối quan hệ và hành vi trừu tượng. Đó không phải là cách duy nhất để đạt được đa hình. Nguyên mẫu là một cách khác để thể hiện tính đa hình khác với tính kế thừa. JavaScript là một ví dụ về ngôn ngữ sử dụng nguyên mẫu. Tôi tưởng tượng có những cách khác nữa.


3

Kế thừa là một khái niệm liên quan đến tái sử dụng mã. Ví dụ: nếu tôi có một lớp cha nói Animalvà nó chứa các thuộc tính và phương thức nhất định (ví dụ này nói makeNoise()sleep()) và tôi tạo hai lớp con được gọi DogCat. Vì cả chó và mèo đều đi ngủ theo cùng một kiểu (tôi cho rằng), không cần thêm chức năng cho sleep()phương thức trong các lớp con DogCatlớp con do lớp cha cung cấp Animal. Tuy nhiên, một Dogtiếng sủa và Cattiếng meo meoAnimalLớp học có thể có một phương pháp để tạo ra tiếng động, một con chó và một con mèo tạo ra những tiếng động khác nhau liên quan đến nhau và các động vật khác. Vì vậy, cần phải xác định lại hành vi đó cho các loại cụ thể của họ. Do đó định nghĩa về đa hình. Hi vọng điêu nay co ich.


3

Tài liệu của Oracle trích dẫn sự khác biệt chính xác.

kế thừa: Một lớp kế thừa các trường và phương thức từ tất cả các siêu lớp của nó, cho dù trực tiếp hay gián tiếp. Một lớp con có thể ghi đè các phương thức mà nó kế thừa hoặc nó có thể ẩn các trường hoặc các phương thức mà nó kế thừa . (Lưu ý rằng các trường ẩn nói chung là thực hành lập trình xấu.)

Đa hình: đa hình đề cập đến một nguyên tắc trong sinh học, trong đó một sinh vật hoặc loài có thể có nhiều hình thức hoặc giai đoạn khác nhau. Nguyên tắc này cũng có thể được áp dụng cho lập trình hướng đối tượng và các ngôn ngữ như ngôn ngữ Java. Các lớp con của một lớp có thể định nghĩa các hành vi độc đáo của riêng chúng và chia sẻ một số chức năng tương tự của lớp cha.

đa hình không được áp dụng cho các lĩnh vực.

Bài liên quan:

Đa hình vs Overriding vs Quá tải


1

Đa hình là một hiệu ứng của thừa kế . Nó chỉ có thể xảy ra trong các lớp mở rộng lẫn nhau. Nó cho phép bạn gọi các phương thức của một lớp mà không cần biết chính xác loại của lớp. Ngoài ra, đa hình xảy ra trong thời gian chạy .

Ví dụ, ví dụ đa hình Java:

nhập mô tả hình ảnh ở đây

Kế thừa cho phép các lớp dẫn xuất chia sẻ giao diện và mã của các lớp cơ sở của chúng. Nó xảy ra vào thời gian biên dịch .

Ví dụ: Tất cả các lớp trong Nền tảng Java là Hậu duệ của đối tượng (hình ảnh lịch sự của Oracle):

nhập mô tả hình ảnh ở đây

Để tìm hiểu thêm về kế thừa Javađa hình Java


0

Kế thừa là khi lớp A kế thừa tất cả các phương thức / trường được bảo vệ / không công khai từ tất cả các cha mẹ của nó cho đến Object.


0

Nếu bạn sử dụng JAVA, nó đơn giản như thế này:

Đa hình đang sử dụng các phương thức được kế thừa nhưng "Ghi đè" chúng để làm một cái gì đó khác (hoặc giống nhau nếu bạn gọi là siêu nên về mặt kỹ thuật sẽ không đa hình).

Sửa tôi nếu tôi sai.


0

Mục đích chính của đa hình : Để tạo biến tham chiếu cho siêu lớp và giữ đối tượng lớp con => một đối tượng có thể thực hiện nhiều hành vi .

Trong thừa kế , lớp con kế thừa các thuộc tính của siêu lớp .


0

thừa kế là loại đa hình, chính xác trong thực tế thừa kế là đa hình động. Vì vậy, khi bạn loại bỏ quyền thừa kế, bạn không thể ghi đè lên nữa.


0

Với Kế thừa, việc thực hiện được xác định trong siêu lớp - vì vậy hành vi được kế thừa.

class Animal
{
  double location;
  void move(double newLocation)
  {
    location = newLocation;
  }
}

class Dog extends Animal;

Với Đa hình, việc triển khai được xác định trong lớp con - vì vậy chỉ có giao diện được kế thừa.

interface Animal
{
  void move(double newLocation);
}

class Dog implements Animal
{
  double location;
  void move(double newLocation)
  {
    location = newLocation;
  }
}

0

Đa hình đạt được bằng Kế thừa trong Java.

├── Animal
└── (instances)
    ├── Cat
    ├── Hamster
    ├── Lion
    └── Moose

├── interface-for-diet
   ├── Carnivore
   └── Herbivore
├── interface-for-habitat
   ├── Pet
   └── Wild

public class Animal {
    void breath() {
    };
}

public interface Carnivore {
    void loveMeat();
}

public interface Herbivore {
    void loveGreens();
}

public interface Pet {
    void liveInside();
}

public interface Wild {
    void liveOutside();
}

public class Hamster extends Animal implements Herbivore, Pet {

    @Override
    public void liveInside() {
        System.out.println("I live in a cage and my neighbor is a Gerbil");
    }

    @Override
    public void loveGreens() {
        System.out.println("I eat Carrots, Grapes, Tomatoes, and More");
    }
}

public class Cat extends Animal implements Carnivore, Pet {
    @Override
    public void liveInside() {
        System.out.println("I live in a cage and my neighbr is a Gerbil");
    }

    @Override
    public void loveMeat() {
        System.out.println("I eat Tuna, Chicken, and More");
    }
}

public class Moose extends Animal implements Herbivore, Wild {

    @Override
    public void liveOutside() {
        System.out.println("I live in the forest");
    }

    @Override
    public void loveGreens() {
        System.out.println("I eat grass");
    }
}

public class Lion extends Animal implements Carnivore, Wild {

    @Override
    public void liveOutside() {
        System.out.println("I live in the forest");
    }

    @Override
    public void loveMeat() {
        System.out.println("I eat Moose");
    }
}

Hamstergiai cấp kế thừa cấu trúc từ Animal, HerbivorePetđể thể hiện hành vi đa hình của vật nuôi trong nhà.

Catlớp kế thừa cấu trúc từ Animal, CarnivorePetcũng thể hiện hành vi đa hình của vật nuôi trong nhà.

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.