Java教程-详解Java 多态性

Java 中的多态性是一个概念,我们可以通过它以不同的方式执行单个操作。多态性源自两个希腊词:poly 和 morphs。“poly”这个词意味着许多,“morphs”意味着形式。所以多态性意味着多种形式。
Java 中有两种类型的多态:编译时多态和运行时多态。我们可以通过方法重载和方法重写来实现java中的多态性。
如果在Java中重载一个静态方法,就是编译期多态的例子。在这里,我们将重点关注 java 中的运行时多态性。
Java 中的运行时多态性
在运行时多态性中,也称为动态方法调度,调用覆盖方法是在运行时而不是编译时进行解析的过程。通过父类的引用变量调用被重写的方法,方法的实际调用取决于引用变量所引用的对象。
向上转型
其中一种运行时多态性的示例是向上转型,即将父类的引用变量引用子类的对象。例如:
Java 中的运行时多态性
运行时多态性(也称为动态方法调度)是一个过程,在该过程中,对于被重写的方法的调用是在运行时而不是编译时进行解析的。
通过父类的引用变量调用一个被重写的方法,方法的具体调用取决于引用变量所引用的对象。这种确定调用方法的过程称为动态绑定。
换句话说,当我们通过父类的引用变量调用一个方法时,实际执行的是子类中重写的方法,而不是父类中的方法。这使得我们可以在不修改引用变量的情况下,根据实际引用的对象来改变方法的行为。
这种动态方法调度的特性使得代码更加灵活和可扩展,因为它允许我们通过父类类型的引用变量来处理不同子类类型的对象,从而实现多态性。
向上转型
如果 Parent 类的引用变量引用 Child 类的对象,则称为向上转型。例如:
class A{}
class B extends A{}
A a=new B();//向上转型
对于向上转型,我们可以使用类类型或接口类型的引用变量。例如:
interface I{}
class A{}
class B extends A implements I{}
在这里,B类的关系是:
B IS-A A
B IS-A I
B IS-A Object
由于Object是Java中所有类的根类,所以我们可以写成B IS-A Object。
Java 运行时多态性示例
在这个例子中,我们定义了两个类:Bike(摩托车)和Splendor(一种具体型号的摩托车)。Splendor 类继承自 Bike 类,并覆盖(重写)了它的 run() 方法。我们使用父类的引用变量来调用 run() 方法。由于引用变量指向的是子类对象,并且子类重写了父类的方法,因此在运行时调用的是子类的方法。
这种情况下的方法调用是在运行时由 JVM 决定的,而不是在编译时确定的。这就是运行时多态性的体现。通过运行时多态性,我们可以通过父类类型的引用变量来调用不同子类类型的方法,这使得我们的代码更加灵活和可扩展。
class Bike{
void run(){System.out.println("行驶");}
}
class Splendor extends Bike{
void run(){System.out.println("安全行驶60km");}
public static void main(String args[]){
Bike b = new Splendor(); //向上转型
b.run();
}
}
输出:
安全行驶60公里
Java 运行时多态性示例:银行
考虑这样一个场景,其中 Bank 是一个提供获取利率的方法的类。但是,利率可能因银行而异。例如,SBI、ICICI 和 AXIS 银行提供 8.4%、7.3% 和 9.7% 的利率。
注意:此示例也在方法覆盖中给出,但没有向上转型。
class Bank{
float getRateOfInterest(){return 0;}
}
class SBI extends Bank{
float getRateOfInterest(){return 8.4f;}
}
class ICICI extends Bank{
float getRateOfInterest(){return 7.3f;}
}
class AXIS extends Bank{
float getRateOfInterest(){return 9.7f;}
}
class TestPolymorphism{
public static void main(String args[]){
Bank b;
b=new SBI();
System.out.println("SBI 利率:"+b.getRateOfInterest());
b=new ICICI();
System.out.println("ICICI 利率:"+b.getRateOfInterest());
b=new AXIS();
System.out.println("AXIS 利率:"+b.getRateOfInterest());
}
}
输出:
SBI 利率:8.4
ICICI 利率:7.3
AXIS 利率:9.7
Java 运行时多态性示例:Shape
class Shape{
void draw(){System.out.println("绘制...");}
}
class Rectangle extends Shape{
void draw(){System.out.println("绘制矩形...");}
}
class Circle extends Shape{
void draw(){System.out.println("绘制圆形...");}
}
class Triangle extends Shape{
void draw(){System.out.println("绘制三角形...");}
}
class TestPolymorphism2{
public static void main(String args[]){
Shape s;
s=new Rectangle();
s.draw();
s=new Circle();
s.draw();
s=new Triangle();
s.draw();
}
}
输出:
绘制矩形...
绘制圆形...
绘制三角形...
Java 运行时多态性示例:Animal
class Animal{
void eat(){System.out.println("正在吃...");}
}
class Dog extends Animal{
void eat(){System.out.println("正在吃面包...");}
}
class Cat extends Animal{
void eat(){System.out.println("正在吃老鼠...");}
}
class Lion extends Animal{
void eat(){System.out.println("正在吃肉...");}
}
class TestPolymorphism3{
public static void main(String[] args){
Animal a;
a=new Dog();
a.eat();
a=new Cat();
a.eat();
a=new Lion();
a.eat();
}}
输出:
正在吃面包...
正在吃老鼠...
正在吃肉...
具有数据成员的 Java 运行时多态性
在Java中,运行时多态性主要适用于方法的覆盖(重写),而不适用于数据成员。数据成员不参与多态性的实现,因为它们是对象的属性,而不是方法的行为。
在下面的示例中,我们有两个类:Vehicle(车辆)和Car(汽车)。这两个类都有一个数据成员speedLimit(速度限制)。我们通过使用父类的引用变量来访问子类对象的数据成员。由于数据成员无法被覆盖,所以无论我们引用的是父类对象还是子类对象,它们访问的都是各自类的数据成员。
规则:数据成员不能实现运行时多态性。
class Bike{
int speedlimit=90;
}
class Honda3 extends Bike{
int speedlimit=150;
public static void main(String args[]){
Bike obj=new Honda3();
System.out.println(obj.speedlimit);//90
}
输出:
90
具有多级继承的 Java 运行时多态性
让我们看一下具有多级继承的运行时多态性的简单示例。
class Animal{
void eat(){System.out.println("正在吃");}
}
class Dog extends Animal{
void eat(){System.out.println("吃水果");}
}
class BabyDog extends Dog{
void eat(){System.out.println("喝牛奶");}
public static void main(String args[]){
Animal a1,a2,a3;
a1=new Animal();
a2=new Dog();
a3=new BabyDog();
a1.eat();
a2.eat();
a3.eat();
}
}
输出:
吃
吃水果
喝牛奶
尝试输出
class Animal{
void eat(){System.out.println("动物正在吃东西...");}
}
class Dog extends Animal{
void eat(){System.out.println("狗正在吃东西...");}
}
class BabyDog1 extends Dog{
public static void main(String args[]){
Animal a=new BabyDog1();
a.eat();
}}
输出:
狗正在吃东西
因为,BabyDog 没有覆盖 eat() 方法,所以调用了 Dog 类的 eat() 方法。