Bất cứ ai cũng có thể cung cấp một ví dụ đơn giản giải thích sự khác biệt giữa đa hình động và tĩnh trong Java?
Bất cứ ai cũng có thể cung cấp một ví dụ đơn giản giải thích sự khác biệt giữa đa hình động và tĩnh trong Java?
Câu trả lời:
Đa hình
1. Liên kết tĩnh / Liên kết thời gian biên dịch / Liên kết sớm / Quá tải phương thức. (Trong cùng một lớp)
2. Liên kết động / Liên kết thời gian chạy / Liên kết trễ / Ghi đè phương thức. (Trong các lớp khác nhau)
class Calculation {
void sum(int a,int b){System.out.println(a+b);}
void sum(int a,int b,int c){System.out.println(a+b+c);}
public static void main(String args[]) {
Calculation obj=new Calculation();
obj.sum(10,10,10); // 30
obj.sum(20,20); //40
}
}
class Animal {
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move();//output: Animals can move
b.move();//output:Dogs can walk and run
}
}
Animal reference but Dog object
, tại sao chúng ta không thể sử dụng Dog reference and dog object
?
Quá tải phương thức sẽ là một ví dụ về đa hình tĩnh
trong khi ghi đè sẽ là một ví dụ về đa hình động.
Bởi vì, trong trường hợp quá tải, tại thời điểm biên dịch, trình biên dịch sẽ biết phương thức nào để liên kết với cuộc gọi. Tuy nhiên, nó được xác định trong thời gian chạy cho đa hình động
Đa hình động (thời gian chạy) là đa hình tồn tại trong thời gian chạy. Ở đây, trình biên dịch Java không hiểu phương thức nào được gọi tại thời điểm biên dịch. Chỉ JVM quyết định phương thức nào được gọi vào thời gian chạy. Quá tải phương thức và ghi đè phương thức bằng các phương thức thể hiện là ví dụ cho đa hình động.
Ví dụ,
Hãy xem xét một ứng dụng nối tiếp và khử tuần tự các loại tài liệu khác nhau.
Chúng ta có thể có 'Tài liệu' là lớp cơ sở và các loại loại tài liệu khác nhau xuất phát từ nó. Ví dụ: XMLDocument, WordDocument, v.v.
Lớp tài liệu sẽ định nghĩa các phương thức 'serialize ()' và 'De-serialize ()' là ảo và mỗi lớp dẫn xuất sẽ thực hiện các phương thức này theo cách riêng của nó dựa trên nội dung thực tế của tài liệu.
Khi các loại tài liệu khác nhau cần được tuần tự hóa / khử tuần tự, các đối tượng tài liệu sẽ được tham chiếu bởi tham chiếu lớp 'Tài liệu' (hoặc con trỏ) và khi phương thức 'Nối tiếp ()' hoặc 'Khử nối tiếp ()' được gọi trên đó, các phiên bản thích hợp của các phương thức ảo được gọi.
Đa hình tĩnh (thời gian biên dịch) là đa hình được thể hiện tại thời gian biên dịch. Ở đây, trình biên dịch Java biết phương thức nào được gọi. Phương thức nạp chồng và phương thức ghi đè bằng phương thức tĩnh; ghi đè phương thức bằng các phương thức riêng tư hoặc cuối cùng là các ví dụ cho đa hình tĩnh
Ví dụ,
Một đối tượng nhân viên có thể có hai phương thức print () một không có đối số và một lấy chuỗi tiền tố được hiển thị cùng với dữ liệu nhân viên.
Với các giao diện này, khi phương thức print () được gọi mà không có bất kỳ đối số nào, trình biên dịch, nhìn vào các đối số hàm sẽ biết hàm nào được gọi và nó tạo ra mã đối tượng tương ứng.
Để biết thêm chi tiết xin vui lòng đọc "Đa hình là gì" (Google nó).
Binding đề cập đến liên kết giữa gọi phương thức và định nghĩa phương thức.
Bức ảnh này cho thấy rõ ràng những gì là ràng buộc.
Trong ảnh này, cuộc gọi của ai a1.methodOne () của ràng buộc ràng buộc với định nghĩa phương thứcOne () tương ứng và cuộc gọi của a1.methodTwo () của ràng buộc với định nghĩa tương ứng của phương thứcTwo ().
Đối với mỗi cuộc gọi phương thức nên có định nghĩa phương thức thích hợp. Đây là một quy tắc trong java. Nếu trình biên dịch không thấy định nghĩa phương thức phù hợp cho mỗi lệnh gọi phương thức, nó sẽ báo lỗi.
Bây giờ, đến với liên kết tĩnh và liên kết động trong java.
Liên kết tĩnh trong Java:
Liên kết tĩnh là một ràng buộc xảy ra trong quá trình biên dịch. Nó cũng được gọi là ràng buộc sớm vì ràng buộc xảy ra trước khi một chương trình thực sự chạy
.
Liên kết tĩnh có thể được thể hiện như trong hình dưới đây.
Trong ảnh này, 'a1' là biến tham chiếu của loại A chỉ vào đối tượng của lớp A. 'a2' cũng là biến tham chiếu của loại A nhưng chỉ vào đối tượng của lớp B.
Trong quá trình biên dịch, trong khi liên kết, trình biên dịch không kiểm tra loại đối tượng mà một biến tham chiếu cụ thể đang trỏ tới. Nó chỉ kiểm tra loại biến tham chiếu thông qua đó một phương thức được gọi và kiểm tra xem có tồn tại một định nghĩa phương thức cho nó trong loại đó không.
Ví dụ, đối với cuộc gọi phương thức của a1.method () trong hình trên, trình biên dịch sẽ kiểm tra xem có tồn tại định nghĩa phương thức cho phương thức () trong Lớp A. Vì 'a1 ′ là loại A không. Tương tự, đối với lệnh gọi phương thức của a a a.method (), nó kiểm tra xem có tồn tại định nghĩa phương thức cho phương thức () trong lớp A. Bởi vì 'a2 cũng là loại A. Nó không kiểm tra đối tượng nào, 'a1' và 'a2' đang trỏ. Loại liên kết này được gọi là liên kết tĩnh.
Liên kết động trong Java:
Liên kết động là một ràng buộc xảy ra trong thời gian chạy. Nó cũng được gọi là ràng buộc muộn vì ràng buộc xảy ra khi chương trình thực sự đang chạy.
Trong thời gian chạy đối tượng thực tế được sử dụng để ràng buộc. Ví dụ, đối với cuộc gọi của a1 amet.method () trong hình trên, phương thức () của đối tượng thực tế mà 'a1' đang trỏ sẽ được gọi. Đối với cuộc gọi a2.method () của cuộc gọi, phương thức () của đối tượng thực tế mà 'a2' đang trỏ sẽ được gọi. Loại ràng buộc này được gọi là ràng buộc động.
Các ràng buộc động của ví dụ trên có thể được chứng minh như dưới đây.
Tham chiếu tĩnh-ràng buộc-và-động-ràng buộc-trong-java
Đa hình: Đa hình là khả năng của một đối tượng có nhiều dạng. Việc sử dụng đa hình phổ biến nhất trong OOP xảy ra khi tham chiếu lớp cha được sử dụng để chỉ đối tượng lớp con.
Liên kết động / Đa hình thời gian chạy:
Thời gian chạy đa hình còn được gọi là phương thức ghi đè. Trong Cơ chế này, theo đó một cuộc gọi đến chức năng bị ghi đè được giải quyết tại Thời gian chạy.
public class DynamicBindingTest {
public static void main(String args[]) {
Vehicle vehicle = new Car(); //here Type is vehicle but object will be Car
vehicle.start(); //Car's start called because start() is overridden method
}
}
class Vehicle {
public void start() {
System.out.println("Inside start method of Vehicle");
}
}
class Car extends Vehicle {
@Override
public void start() {
System.out.println("Inside start method of Car");
}
}
Đầu ra:
Phương pháp khởi động bên trong xe
Đa hình tĩnh / đa hình thời gian biên dịch:
Phương thức nào được gọi chỉ được quyết định tại thời điểm biên dịch.
public class StaticBindingTest {
public static void main(String args[]) {
Collection c = new HashSet();
StaticBindingTest et = new StaticBindingTest();
et.sort(c);
}
//overloaded method takes Collection argument
public Collection sort(Collection c){
System.out.println("Inside Collection sort method");
return c;
}
//another overloaded method which takes HashSet argument which is sub class
public Collection sort(HashSet hs){
System.out.println("Inside HashSet sort method");
return hs;
}
}
Đầu ra: Inside Collection sort metho
nạp chồng phương thức là một ví dụ về thời gian biên dịch / đa hình tĩnh bởi vì liên kết phương thức giữa lệnh gọi phương thức và định nghĩa phương thức xảy ra tại thời gian biên dịch và nó phụ thuộc vào tham chiếu của lớp (tham chiếu được tạo tại thời gian biên dịch và đi đến ngăn xếp).
ghi đè phương thức là một ví dụ về thời gian chạy / đa hình động vì liên kết phương thức giữa lệnh gọi phương thức và định nghĩa phương thức xảy ra trong thời gian chạy và nó phụ thuộc vào đối tượng của lớp (đối tượng được tạo trong thời gian chạy và đi vào heap).
Nói một cách đơn giản:
Đa hình tĩnh : Tên phương thức giống nhau bị quá tải với loại hoặc số lượng tham sốkhác nhautrong cùng một lớp (chữ ký khác nhau). Cuộc gọi phương thức được nhắm mục tiêu được giải quyết tại thời gian biên dịch.
Đa hình động : Cùng một phương thức được ghi đè bằng cùng một chữ ký trong các lớp khác nhau . Loại đối tượng mà phương thức đang được gọi không được biết tại thời điểm biên dịch nhưng sẽ được quyết định khi chạy.
Nói chung, quá tải sẽ không được coi là đa hình.
Từ trang hướng dẫn java :
Các lớp con của một lớp có thể định nghĩa các hành vi duy nhất của riêng chúng và chia sẻ một số chức năng tương tự của lớp cha
Generally overloading won't be considered as polymorphism.
bạn có thể vui lòng giải thích về điểm này
Quá tải phương thức được gọi là Đa hình tĩnh và còn được gọi là Đa hình thời gian biên dịch hoặc Liên kết tĩnh vì các lệnh gọi phương thức bị quá tải được giải quyết tại thời gian biên dịch trên cơ sở danh sách đối số và tham chiếu mà chúng ta đang gọi phương thức.
Và phương pháp trọng được gọi là động Polymorphism hoặc đơn giản Polymorphism hoặc Runtime Phương pháp văn hoặc động Binding vì ghi đè phương pháp gọi được giải quyết trong thời gian chạy.
Để hiểu lý do tại sao điều này là như vậy, hãy lấy một ví dụ về Mammal
và Human
lớp
class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
class Human extends Mammal {
@Override
public void speak() { System.out.println("Hello"); }
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
}
Tôi đã bao gồm đầu ra cũng như mã byte trong các dòng mã bên dưới
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
Và bằng cách nhìn vào đoạn mã trên, chúng ta có thể thấy rằng các mã byte của humanMammal.speak (), human.speak () và human.speak ("Hindi") hoàn toàn khác nhau vì trình biên dịch có thể phân biệt giữa chúng dựa trên danh sách đối số và tham khảo lớp học. Và đây là lý do tại sao Phương thức quá tải được gọi là đa hình tĩnh .
Nhưng mã byte cho anyMammal.speak () và humanMammal.speak () là như nhau bởi vì theo trình biên dịch, cả hai phương thức đều được gọi trên tham chiếu Mammal nhưng đầu ra cho cả hai lệnh gọi phương thức là khác nhau vì trong thời gian chạy JVM biết đối tượng nào đang tham chiếu và JVM gọi phương thức trên đối tượng và đây là lý do tại sao Phương thức ghi đè được gọi là Đa hình động.
Vì vậy, từ mã trên và mã byte, rõ ràng rằng trong quá trình gọi pha, phương thức gọi được xem xét từ kiểu tham chiếu. Nhưng tại thời điểm thực hiện phương thức sẽ được gọi từ đối tượng mà tham chiếu đang giữ.
Nếu bạn muốn biết thêm về điều này, bạn có thể đọc thêm về Cách JVM xử lý quá tải và ghi đè nội bộ .
Đa hình tĩnh: là nơi quyết định giải quyết phương pháp nào cần thực hiện, được xác định trong thời gian biên dịch. Phương thức Quá tải có thể là một ví dụ về điều này.
Đa hình động: là nơi quyết định chọn phương thức thực thi, được đặt trong thời gian chạy. Phương pháp ghi đè có thể là một ví dụ về điều này.
Đa hình đề cập đến khả năng của một đối tượng hành xử khác nhau cho cùng một kích hoạt.
Đa hình tĩnh (Đa hình thời gian biên dịch)
Đa hình động (Đa hình thời gian chạy)
Biên dịch đa hình thời gian (Binding tĩnh / Binding sớm): Trong đa hình tĩnh, nếu chúng ta gọi một phương thức trong mã của mình thì định nghĩa của phương thức đó sẽ được gọi thực sự chỉ được giải quyết tại thời gian biên dịch.
(hoặc là)
Tại thời điểm biên dịch, Java biết nên gọi phương thức nào bằng cách kiểm tra chữ ký của phương thức. Vì vậy, đây được gọi là đa hình thời gian biên dịch hoặc liên kết tĩnh.
Đa hình động (Liên kết muộn / Đa hình thời gian chạy ): Trong thời gian chạy, Java đợi cho đến khi thời gian chạy để xác định đối tượng nào thực sự được trỏ đến bởi tham chiếu. Phương pháp giải quyết được thực hiện trong thời gian chạy, do đó chúng tôi gọi là đa hình thời gian chạy.
Hãy xem xét mã dưới đây:
public class X
{
public void methodA() // Base class method
{
System.out.println ("hello, I'm methodA of class X");
}
}
public class Y extends X
{
public void methodA() // Derived Class method
{
System.out.println ("hello, I'm methodA of class Y");
}
}
public class Z
{
public static void main (String args []) {
//this takes input from the user during runtime
System.out.println("Enter x or y");
Scanner scanner = new Scanner(System.in);
String value= scanner.nextLine();
X obj1 = null;
if(value.equals("x"))
obj1 = new X(); // Reference and object X
else if(value.equals("y"))
obj2 = new Y(); // X reference but Y object
else
System.out.println("Invalid param value");
obj1.methodA();
}
}
Bây giờ, nhìn vào mã bạn không bao giờ có thể biết việc triển khai phương thứcA () nào sẽ được thực thi, bởi vì nó phụ thuộc vào giá trị nào mà người dùng đưa ra trong thời gian chạy. Vì vậy, nó chỉ được quyết định trong thời gian chạy là phương thức nào sẽ được gọi. Do đó, đa hình thời gian chạy.
Quá tải phương thức là một đa hình thời gian biên dịch, hãy lấy một ví dụ để hiểu khái niệm này.
class Person //person.java file
{
public static void main ( String[] args )
{
Eat e = new Eat();
e.eat(noodle); //line 6
}
void eat (Noodles n) //Noodles is a object line 8
{
}
void eat ( Pizza p) //Pizza is a object
{
}
}
Trong ví dụ này, Person có một phương pháp ăn thể hiện rằng anh ta có thể ăn Pizza hoặc Mì. Phương thức ăn bị quá tải khi chúng tôi biên dịch Person.java này, trình biên dịch giải quyết cuộc gọi phương thức "e.eat (mì) [ở dòng 6] với định nghĩa phương thức được chỉ định trong dòng 8, đó là phương thức lấy mì làm tham số và toàn bộ quá trình được thực hiện bởi Compiler vì vậy đó là Đa hình thời gian biên dịch. Quá trình thay thế lời gọi phương thức bằng định nghĩa phương thức được gọi là liên kết, trong trường hợp này, nó được trình biên dịch thực hiện để nó được gọi là liên kết sớm.
Theo câu trả lời của Naresh, tính đa hình động chỉ là 'động' trong Java do sự hiện diện của máy ảo và khả năng diễn giải mã trong thời gian chạy thay vì mã chạy tự nhiên.
Trong C ++, nó phải được giải quyết tại thời điểm biên dịch nếu nó được biên dịch thành nhị phân gốc bằng gcc, rõ ràng; tuy nhiên, bước nhảy và thunk trong bảng ảo vẫn được gọi là 'tra cứu' hoặc 'động'. Nếu C kế thừa B và bạn khai báo , c sẽ trỏ đến đối tượng C bên ngoài và con trỏ sẽ được chuyển đến C :: method1 () trong đoạn văn bản. Tham khảo: http : //www.programmers think.com/article/2572545946/B* b = new C(); b->method1();
, b sẽ được trình biên dịch giải quyết để trỏ đến một đối tượng B bên trong C (đối với một lớp đơn giản thừa hưởng một tình huống lớp, đối tượng B bên trong C và C sẽ bắt đầu tại cùng một địa chỉ bộ nhớ là bắt buộc phải được thực hiện, nó sẽ được chỉ vào vptr mà cả hai đều sử dụng). Nếu C kế thừa B và A, bảng chức năng ảo của đối tượng A bên trong mục C cho phương thức 1 sẽ có một thunk sẽ bù con trỏ vào đầu của đối tượng C được đóng gói và sau đó chuyển nó sang A :: method1 () thực. trong đoạn văn bản mà C đã ghi đè. Dành choC* c = new C(); c->method1()
Trong java, for B b = new C(); b.method1();
, máy ảo có thể tự động kiểm tra loại đối tượng được ghép với b và có thể truyền đúng con trỏ và gọi phương thức đúng. Bước bổ sung của máy ảo giúp loại bỏ sự cần thiết của các bảng chức năng ảo hoặc loại được giải quyết tại thời gian biên dịch, ngay cả khi có thể biết được tại thời điểm biên dịch. Đó chỉ là một cách làm khác, điều này có ý nghĩa khi một máy ảo có liên quan và mã chỉ được biên dịch thành mã byte.