[英]Run-time Polymorphism in Java without “abstract”?
我正在阅读Oracle官方教程,其中以3个类的类层次结构为例介绍了多态性的概念。 自行车是超类,MountainBike和RoadBike是两个子类。
它显示了这两个子类如何通过声明其不同版本来覆盖Bicycle中声明的方法“ printDescription”。
最后,在最后,本教程提到Java虚拟机(JVM)为每个变量中引用的对象调用适当的方法。
但是,关于多态的教程中没有任何地方提到“抽象”类和方法的概念。 除非在Bicycle中将printDescription()声明为“抽象”,否则如何实现运行时多态? 我的意思是,在给出此示例的情况下,基于什么提示,编译器是否决定在编译时不将方法调用绑定到引用类型,并认为应该让它在运行时让JVM处理?
下面是使用的示例:
public class Bicycle {
public int cadence;
public int gear;
public int speed;
public Bicycle(int startCadence, int startSpeed, int startGear) {
gear = startGear;
cadence = startCadence;
speed = startSpeed;
}
public void setCadence(int newValue) {
cadence = newValue;
}
public void setGear(int newValue) {
gear = newValue;
}
public void applyBrake(int decrement) {
speed -= decrement;
}
public void speedUp(int increment) {
speed += increment;
}
public void printDescription(){
System.out.println("\nBike is " + "in gear " + this.gear
+ " with a cadence of " + this.cadence +
" and travelling at a speed of " + this.speed + ". ");
}
}
public class MountainBike extends Bicycle {
private String suspension;
public MountainBike(
int startCadence,
int startSpeed,
int startGear,
String suspensionType){
super(startCadence,
startSpeed,
startGear);
this.setSuspension(suspensionType);
}
public String getSuspension(){
return this.suspension;
}
public void setSuspension(String suspensionType) {
this.suspension = suspensionType;
}
public void printDescription() {
super.printDescription();
System.out.println("The " + "MountainBike has a" +
getSuspension() + " suspension.");
}
}
public class RoadBike extends Bicycle{
private int tireWidth;
public RoadBike(int startCadence,
int startSpeed,
int startGear,
int newTireWidth){
super(startCadence,
startSpeed,
startGear);
this.setTireWidth(newTireWidth);
}
public int getTireWidth(){
return this.tireWidth;
}
public void setTireWidth(int newTireWidth){
this.tireWidth = newTireWidth;
}
public void printDescription(){
super.printDescription();
System.out.println("The RoadBike"
" has " + getTireWidth() +
" MM tires.");
}
}
public class TestBikes {
public static void main(String[] args){
Bicycle bike01, bike02, bike03;
bike01 = new Bicycle(20, 10, 1);
bike02 = new MountainBike(20, 10, 5, "Dual");
bike03 = new RoadBike(40, 20, 8, 23);
bike01.printDescription();
bike02.printDescription();
bike03.printDescription();
}
}
除非在Bicycle中将printDescription()声明为“抽象”,否则如何实现运行时多态?
您为什么认为抽象类会改变任何东西? 抽象类做两件事
注意,除非在基类上抽象地声明了一个方法,否则第二点并不意味着多态性将无法工作。 相反,它为开发人员提供了强制子类提供实现的机会,这在不涉及任何抽象用法的子类化场景中是不需要的。
而已。 换句话说,抽象的概念使Java的多态性得到了补充-它是一种语言功能,但与Java在运行时用于调用方法的动态调度没有任何关系。 每当在实例上调用方法时,运行时实例的类型将用于确定要使用的方法实现。
在Java中,所有方法都在运行时绑定(这是在C ++中将方法声明为虚拟方法可以实现的功能)。
因此,JVM始终可以正确地分派该方法。
实际上,Java中的方法绑定永远不会是静态的,因为您总是要处理对对象的引用(不能像C ++那样在堆栈上分配对象)。 这实际上迫使JVM始终检查对象引用的运行时类型。
virtual
是许多语言的关键字,表示“该方法可以被子类覆盖”。 Java没有该关键字,但是所有非静态成员方法都是虚拟的,可以覆盖 。
abstract
与virtual相同,不同之处在于abstract
告诉编译器基类没有该方法的定义。 有时,如果没有有用的函数可以执行基类,那么它很有用,但是并不需要覆盖基类方法。
在您的情况下,printDescription方法为基类提供了有用的定义,因此无需将其声明为抽象的。 默认情况下它是虚拟的,因此可以被子类覆盖,因此不需要关键字来表明这一点。
在运行时多态中,将根据基类引用所指向的类实例来调用适当的派生类方法。
考虑以下示例:-
class A {
public void doSomething() {
}
}
class B extends A {
public void doSomething() {
System.out.println("In B")
}
}
public class Test {
public static void main(String args[]) {
A obj = new B(); // Base class reference and derived class object.
obj.doSomething(); // Calls derived class B's method and prints `In B`
}
}
引用您阅读的声明:-
本教程提到Java虚拟机(JVM)为每个变量中引用的对象调用适当的方法。
为了证明以上陈述的合理性,请参见以上示例。 因为您的基类引用obj
指向派生类B's
实例,所以将调用您的B类方法。
始终在编译时检查指向该对象的引用的类型,而在运行时检查该引用所指向的对象的类型。
因此,这些方法将被调用的决定 在运行时做出。 。 不管你的基类的方法是abstract
或没有 ,适当的派生类的方法被调用..
这不是C ++。 在Java中,您总是知道每个实例的真实类,因此,在调用printDescription()
时,将使用该类的定义。 不过,您只能使用实例引用中的可用方法(因此,如果您在RoadBike
类中定义了方法getMPH()
,并且使用Bike
变量处理该类的实例,则编译器将发出错误消息。打算使用它)。
我认为这段代码:
bike01 = new Bicycle(20, 10, 1);
bike02 = new MountainBike(20, 10, 5, "Dual");
bike03 = new RoadBike(40, 20, 8, 23);
bike01.printDescription();
bike02.printDescription();
bike03.printDescription();
这不是运行时多态性的最佳示例,因为即使在编译时,所有事实(调用方法)也是已知的。 但是,如果您将其更改为:
Random r = new Random();
if(r.nextInt(2)%2==0)
{
bike01 = new Bicycle(20, 10, 1)
}
else
{
bike01 = new MountainBike(20, 10, 5, "Dual");
}
// only at run-time the right function to call is known
bike01.printDescription();
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.