Java多态
-
多态基础
Java 多态,多态是面向对象特征之一,它允许我们以不同的方式执行单个动作。例如,假设我们有一个
Animal
类,它有一个方法sound()
。由于这是一个泛型类,所以我们不能给它一个实现,如:汪汪
,喵喵
等。我们不得不给出一个通用的消息。
public class Animal{
...
public void sound(){
System.out.println("动物有各种各样的声音");
}
}
现在假设我们动物类的两个子类:
Dog
和Cat
扩展Animal
类。我们可以提供相同的方法实现
public class Dog extends Animal{
...
@Override
public void sound(){
System.out.println("汪汪");
}
}
public class Cat extends Animal{
...
@Override
public void sound(){
System.out.println("喵喵");
}
}
尽管我们对所有子类
sound()
都有共同的操作,但是有不同的方法来执行相同的操作。这是多态的完美示例(允许我们以不同方式执行单个操作的功能)。仅调用泛型sound()
方法没有任何意义,因为每个Animal
都有不同的声音
-
运行时多态和编译时多态
-
java 中有两种类型的多态:
-
静态多态又称编译时多态
-
动态多态又称运行时多态
-
-
运行时多态(静态多态)
在编译器时间内解析的多态称为静态多态。方法重载是编译时多态的一个例子。
方法重载:如果方法的参数在参数的数量,顺序和数据类型上不同,这允许我们有多个具有相同名称的方法。
-
静态多态的例子
方法重载是Java支持静态多态的方式之一。这里有两个相同的方法
add()
的定义,其中add()
方法的使用将在编译时由参数列表决定。class Calculator { int output(int a) { return a; } int add(int a, int b) { return a+b; } int multiplication(int a, int b) { return a*b; } } public class Demo { public static void main(String args[]) { Calculator obj = new Calculator(); System.out.println(obj.output(10)); System.out.println(obj.add(10,20)); System.out.println(obj.multiplication(10,20)); } }
输出
10 30 300
-
运行时多态(动态多态)
它也称为动态方法调度。动态多态是一个在运行时解析对重写方法的调用的过程。
例:
有两个类
ABC
和XYZ
。ABC
是父类,XYZ
是子类。子类覆盖父类的myMethod()
方法。将子类对象分配给父类引用,因此为了确定将调用哪个方法,将在运行时确定对象的类型。对象的类型决定了要调用哪个版本的方法(而不是引用的类型)。class ABC{ public void myMethod(){ System.out.println("方法一"); } } public class XYZ extends ABC{ public void myMethod(){ System.out.println("方法二"); } public static void main(String args[]){ ABC obj = new XYZ(); obj.myMethod(); } }
输出:
方法二
几个通俗易懂的例子:
ABC obj = new ABC(); obj.myMethod(); // 调用ABC的myMethod XYZ obj = new XYZ(); obj.myMethod(); // 调用XYZ的myMethod ABC obj = new XYZ(); obj.myMethod(); // 调用XYZ的myMethod
Java的静态和动态绑定
-
静态绑定
编译器在编译时可以解析的绑定称为静态或早期绑定。
static
,private
和final
方法的绑定是编译时。 因为是无法覆盖这些方法,并且在编译时确定类的类型。-
静态绑定示例
有两个类,人类和男孩。这两个类都有相同的方法
walk()
,但方法是静态的,这意味着它不能被覆盖,所以即使我在创建对象obj
时使用了Boy
类的对象,它也会调用父类方法。因为引用是Human
类型(父类)。因此,每当静态,私有和最终方法的绑定发生时,类的类型由编译器在编译时确定,然后绑定发生在那里。class Human{ public static void walk() { System.out.println("Human walks"); } } class Boy extends Human{ public static void walk(){ System.out.println("Boy walks"); } public static void main( String args[]) { Human obj = new Boy(); Human obj2 = new Human(); obj.walk(); obj2.walk(); } }
输出:
Human walks Human walks
-
动态绑定
当编译器无法在编译时解析调用/绑定时,此类绑定称为动态绑定或后期绑定。方法覆盖是动态绑定的一个完美示例,因为覆盖父类和子类具有相同的方法,在这种情况下,对象的类型确定要执行的方法。对象的类型在运行时确定,因此称为动态绑定。
动态绑定示例
class Human{ //Overridden Method public void walk() { System.out.println("Human walks"); } } class Demo extends Human{ //Overriding Method public void walk(){ System.out.println("Boy walks"); } public static void main( String args[]) { Human obj = new Demo(); Human obj2 = new Human(); obj.walk(); obj2.walk(); } }
输出:
Boy walks Human walks
-
静态绑定与动态绑定的差异
- 静态绑定在编译时发生,而动态绑定在运行时发生。
- 私有,静态和最终方法的绑定总是在编译时发生,因为这些方法无法被覆盖。当实际发生方法覆盖并将父类型的引用分配给子类类型的对象时,则在运行时期间解析此类绑定。
- 重载方法的绑定是静态的,并且覆盖方法的绑定是动态的
-