有人能提供一个简单的例子来说明Java中动态和静态多态之间的区别吗?
有人能提供一个简单的例子来说明Java中动态和静态多态之间的区别吗?
多态性
1. 静态绑定/编译时绑定/早期绑定/方法重载(在同一类中)。
2. 动态绑定/运行时绑定/晚期绑定/方法覆盖(在不同的类中)。
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
类的引用来引用Dog
对象是合法的。这种做法有助于编写通用代码,提高可重用性和可扩展性。如果使用Dog
类的引用来引用Dog
对象,则会限制代码的灵活性,使得以后难以将代码扩展到涉及其他动物类型的情况。 - lu5er方法重载是静态多态性的一个例子。
而覆盖则是动态多态性的一个例子。
因为在重载的情况下,编译器在编译时知道要链接到哪个方法。然而,在动态多态性中,这是在运行时确定的。
动态(运行时)多态性是在运行时存在的多态性。在这里,Java编译器不知道哪个方法在编译时被调用。只有JVM决定在运行时调用哪个方法。方法重载和实例方法使用的方法覆盖是动态多态性的示例。
例如
考虑一个序列化和反序列化不同类型文档的应用程序。
我们可以将‘ Document’作为基类,并从中派生不同的文档类型类。例如:XML文档、Word文档等
Document类将定义‘ Serialize()’和‘ De-serialize()’方法为虚拟方法,每个派生类将根据文档的实际内容以自己的方式实现这些方法。
当需要序列化/反序列化不同类型的文档时,将通过‘ Document’类引用(或指针)引用文档对象,当对其调用‘ Serialize()’或‘ De-serialize()’方法时,将调用适当版本的虚拟方法。
静态(编译时)多态性是在编译时表现出的多态性。在这里,Java编译器知道哪个方法被调用。使用静态方法的方法重载和方法覆盖;使用私有或final方法的方法覆盖是静态多态性的示例。
例如
一个员工对象可能有两个print()方法,一个不带参数,另一个带有前缀字符串以与员工数据一起显示。
给定这些接口,当没有任何参数调用print()方法时,编译器根据函数参数知道应该调用哪个函数,并相应地生成对象代码。
有关更多详细信息,请阅读“什么是多态性”(在Google上搜索)。
.
静态绑定可以像下面的图片一样演示。
在这张图片中,“a1”是指向Class A对象的Class A类型的引用变量。 “a2”也是Class A类型的引用变量,但指向Class B的对象。方法重载是编译时/静态多态性的一个例子,因为方法调用和方法定义之间的绑定发生在编译时,并且它取决于类的引用(引用在编译时创建并进入堆栈)。
方法重写是运行时/动态多态性的一个例子,因为方法调用和方法定义之间的绑定发生在运行时,并且它取决于类的对象(对象在运行时创建并进入堆内存)。
Mammal
和Human
类的例子。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");
}
}
我已经在下面的代码行中包含了输出和字节码
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
通过观察上述代码,我们可以看到 humanMammal.speak()、human.speak() 和 human.speak("Hindi") 的字节码完全不同,因为编译器能够根据参数列表和类引用进行区分。这就是为什么 方法重载 被称为 静态多态性 的原因。
静态多态性:在同一类中,使用不同的类型或数量的参数重载了相同的方法名(不同的签名)。目标方法调用在编译时解析。
动态多态性:在不同的类中使用相同的签名 覆盖了相同的方法。在编译时无法确定调用该方法的对象类型,但会在运行时决定。
通常情况下,重载不被认为是多态性。
来自Java教程页面:
一个类的子类可以定义其自己独特的行为,同时共享父类的某些功能
多态性: 多态性是指一个对象具有多种形式的能力。在面向对象编程中,最常见的多态性使用方式是使用父类引用来引用子类对象。
动态绑定/运行时多态性:
运行时多态性也称为方法重写。在这种机制中,对重写函数的调用是在运行时解决的。
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");
}
}
输出:
在Car的start方法内部
静态绑定/编译时多态:
方法调用的决定只在编译时进行。
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;
}
}
静态多态:是指在编译时确定要执行的方法决策。方法重载可以作为此类的一个例子。
动态多态:是指在运行时确定要执行的方法决策。方法重写可以作为此类的一个例子。