我知道在方法覆盖的情况下会发生多态。 但我对下面的内容感到有些困惑。
class A {
public void hi() {
System.out.println("A "+this.getClass().getName());
}
}
class B extends A {
public void bye() {
System.out.println("B "+this.getClass().getName());
}
}
class Ideone {
public static void main (String[] args) throws java.lang.Exception {
A a = new B();
a.hi();
a.bye();
}
}
输出:
Main.java:35: error: cannot find symbol
a.bye();
^
symbol: method bye()
location: variable a of type A
1 error
为什么会出现编译时错误?
在a = new B()
中,B
类对象是在运行时创建的,因此a
是一个指向B
类型对象的引用变量。
现在,如果我们调用B
的类方法bye()
,为什么它是编译器时间错误?
答案 0 :(得分:2)
a
变量可能在运行时包含类A
的实例或A
的任何子类。因此,您只能为该变量调用类A
的方法。
编译器在确定哪些方法调用有效时,只关心变量的编译时类型。
答案 1 :(得分:2)
变量a
的声明类型是A.编译器不知道(也不应该知道)它在运行时的具体类型是什么B.它只知道它是A,并且A中没有bye()
方法。
完成的重点
A a = new B();
而不是
B a = new B();
要清楚地说a是A,并且可以有任何具体类型,只要conrete类型扩展A.如果你以后找到更好的A实现,你必须能够将该行更改为
a a = new BetterImplementation();
并编译代码。
答案 2 :(得分:0)
多态性基本上是一个对象采取多种形式的能力。由于您的父类是指子类对象,因此它是多态的。
Main.java:35: error: cannot find symbol
a.bye();
^
symbol: method bye()
location: variable a of type A
1 error
您收到此错误是因为您尝试从超类引用中调用子类的方法。
在这里,您将subClass对象ref分配给超类,这很好。 但超类只能调用它自己已知的方法和数据。
A a = new B();
a.hi(); // member of super class
a.bye(); // Not a member a super class
答案 3 :(得分:0)
将新的B
实例分配给类型为A
的引用,就像让它佩戴唯一的方法定义的A眼镜一样。那就是你得到了A
所描述的界面。即使该实例具有bye
的实现,您也只能访问hi
。
答案 4 :(得分:0)
理解这一点的一个简单方法是A a实际上可能指向B的对象,但在编译期间,编译器并不知道。
编译器只检查引用,即' a'并看看它的班级,即' A'有一个方法,它的参考' a'正打算打电话。
在您的情况下,参考' a'没有一个名为bye()的方法,所以根据编译器不能进行这样的调用,这就是你看到错误的原因。
答案 5 :(得分:0)
我认为你已经从其他答案得到了你的多态性问题的答案。除此之外,您还可以通过类型转换使代码以这种方式工作。
(B)a.bye();
答案 6 :(得分:0)
您只能从父类类型访问父类方法。
A a = new B();
解决方案1:
将父级更改为子级(B b = new B ()
)并调用B方法。
解决方案2:
检查parent是否是Child对象的实例。如果是,则将父项转换为Child并调用方法。
class Ideone {
public static void main (String[] args) throws java.lang.Exception {
A a = new B();
a.hi();
if ( a instanceof B){
((B)a).bye();
}
}
}
输出:
A B
B B
上的oracle文档页面
instanceof运算符将对象与指定类型进行比较。您可以使用它来测试对象是否是类的实例,子类的实例或实现特定接口的类的实例。