Pra*_*ena 108 java oop polymorphism overriding overloading
任何人都可以提供一个简单的例子来解释Java中动态和静态多态的区别吗?
KhA*_*aAb 181
多态性
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
}
}
Run Code Online (Sandbox Code Playgroud)
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
}
}
Run Code Online (Sandbox Code Playgroud)
rac*_*ana 15
动态(运行时)多态性是运行时存在的多态性.这里,Java编译器不了解在编译时调用哪个方法.只有JVM决定在运行时调用哪个方法.使用实例方法的方法重载和方法重写是动态多态的示例.
例如,
考虑一个序列化和反序列化不同类型文档的应用程序.
我们可以将'Document'作为基类,并从中派生出不同的文档类型类.例如XMLDocument,WordDocument等.
Document类将'Serialize()'和'De-serialize()'方法定义为virtual,每个派生类将根据文档的实际内容以自己的方式实现这些方法.
当需要序列化/反序列化不同类型的文档时,文档对象将由"Document"类引用(或指针)引用,并且在调用"Serialize()"或"De-serialize()"方法时在其上,调用适当版本的虚拟方法.
静态(编译时)多态性是编译时显示的多态性.这里,Java编译器知道调用哪个方法.使用静态方法重载方法和方法重写; 使用私有或最终方法重写的方法是静态多态的示例
例如,
员工对象可能有两个print()方法,一个不带参数,另一个带前缀字符串以及员工数据.
给定这些接口,当在没有任何参数的情况下调用print()方法时,查看函数参数的编译器知道要调用哪个函数,并相应地生成目标代码.
有关详细信息,请阅读"什么是多态"(Google it).
Els*_*yed 11
绑定是指方法调用和方法定义之间的链接.
这张照片清楚地显示了什么是约束力
在这张图片中,"a1.methodOne()"调用绑定到相应的methodOne()定义,而"a1.methodTwo()"调用绑定到相应的methodTwo()定义.
对于每个方法调用,都应该有适当的方法定义.这是java中的一个规则.如果编译器没有为每个方法调用看到正确的方法定义,则会抛出错误.
现在,来看看java中的静态绑定和动态绑定.
Java中的静态绑定:
静态绑定是在编译期间发生的绑定.它也称为早期绑定,因为绑定发生在程序实际运行之前
.
静态绑定可以如下图所示进行演示.
在这张图片中,'a1'是类A的类型的引用变量,指向类A的对象.'a2'也是类A类的引用变量,但指向类B的对象.
在编译期间,在绑定时,编译器不会检查特定引用变量所指向的对象的类型.它只检查调用方法的引用变量的类型,并检查该类型中是否存在方法定义.
例如,对于上图中的"a1.method()"方法调用,编译器检查A类中是否存在method()的方法定义.因为'a1'是A类类型.类似地,对于"a2.method()"方法调用,它检查A类中是否存在method()的方法定义.因为'a2'也是A类类型.它不会检查"a1"和"a2"指向哪个对象.这种类型的绑定称为静态绑定.
Java中的动态绑定:
动态绑定是在运行时发生的绑定.它也称为后期绑定,因为程序实际运行时会发生绑定.
在运行时,实际对象用于绑定.例如,对于上图中的"a1.method()"调用,将调用'a1'指向的实际对象的method().对于"a2.method()"调用,将调用'a2'指向的实际对象的method().这种类型的绑定称为动态绑定.
以下示例的动态绑定可以如下所示.
方法重载是编译时/静态多态的一个例子,因为方法调用和方法定义之间的方法绑定在编译时发生,它取决于类的引用(在编译时创建的引用并转到堆栈).
方法重写是运行时/动态多态的一个示例,因为方法调用和方法定义之间的方法绑定在运行时发生,它取决于类的对象(在运行时创建的对象并转到堆).
多态性: 多态性是一种物体采取多种形式的能力.当父类引用用于引用子类对象时,OOP中最常见的多态性使用发生.
动态绑定/运行时多态性:
运行时多态性也称为方法覆盖.在此机制中,在运行时解析对重写函数的调用.
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");
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
汽车的内部启动方法
静态绑定/编译时多态:
要调用哪个方法仅在编译时决定.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
输出:Inside Collection sort方法
方法重载被称为静态多态,也称为编译时多态或静态绑定,因为重载的方法调用在编译时由编译器根据参数列表和我们调用方法的引用来解决。
和方法覆盖被称为动态多态性或简单的多态性和运行方法分派或动态绑定,因为重写的方法调用在运行时得到解决。
为了理解为什么会这样,让我们举一个例子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");
}
}
Run Code Online (Sandbox Code Playgroud)
我在下面的代码行中包含了输出和字节码
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
Run Code Online (Sandbox Code Playgroud)
通过查看上面的代码,我们可以看到 humanMammal.speak() 、 human.speak() 和 human.speak("Hindi") 的字节码完全不同,因为编译器能够根据参数列表区分它们和类参考。这就是方法重载被称为静态多态的原因。
但是 anyMammal.speak() 和 humanMammal.speak() 的字节码是相同的,因为根据编译器,这两种方法都是在 Mammal 引用上调用的,但是两种方法调用的输出是不同的,因为在运行时 JVM 知道引用所持有的对象和 JVM 调用对象上的方法,这就是方法覆盖被称为动态多态的原因。
所以从上面的代码和字节码可以看出,在编译阶段调用方法是从引用类型考虑的。但是在执行时方法将从引用持有的对象中调用。
如果您想了解更多相关信息,您可以阅读更多关于JVM 如何在内部处理方法重载和覆盖。
归档时间: |
|
查看次数: |
203078 次 |
最近记录: |