在下面的代码中,我在b.printname();处得到编译器错误。据我所知,错误与编译器有效地以非多态方式操作的事实有关(即编译器基本上只选择查看操作数的左侧,因此b是一个问题)。由于b是Question类型,因为Question没有no-args printName方法,所以会出现编译错误。那是对的吗? 现在假设这是正确的,我的问题是为什么?当然编译器应该知道问题b是指一个实际上支持no-args printName方法的对象?例如。如果你看看编译器在转换方面的表现如何,有些例子表明,编译器由于缺少一个更好的单词,会多态地行为或者以不同的方式将编译器知道正确的方向发生了什么。操作数的一面并根据该知识行事。一个例子是,如果接口类型引用实现接口的对象,则编译器查看语句的右侧(即实现接口的对象)并确定不需要强制转换。那么为什么编译器在这里没有这样做,为什么它看起来并且看到有问题的对象实际上是蓝色而Blue确实支持no-arg方法printName?
public class Polymorf3 {
public static void main(String[] args){
Polymorf3 me = new Polymorf3();
me.doStuff();
}
public void doStuff() {
Bat a = new Bat();
Question b = new Blue();
//a.printName();
a.printName(a.name);
b.printName(); // Compiler Error:Required String Found no args
}
abstract class Question {
String name="Question_name";
public void printName(String name){ System.out.println(name);}
}
class Bat extends Question {
String name = "Bat_Bruce";
//public void printName(){ System.out.println(name);}
}
class Blue extends Question {
String name = "Clark";
public void printName() {System.out.println(name);}
}
}
答案 0 :(得分:1)
虽然b
的类型为Blue
,但由于您将其声明为Question b = new Blue();
,因此编译器将其视为类型Question
,因此这是唯一可用的接口没有明确的演员:
((Blue)b).printName();
或者,您可以将其声明为Blue b = new Blue();
,b.printName();
不会引发编译时错误。
基本上,这里发生的是你在更高的抽象级别声明你的新变量b
,因此printName
可用的唯一b
方法是更高级别的方法抽象层次,与args的抽象层次。
修改强>
OP询问为什么编译器将b
视为Question
,即使它已初始化为Blue
。请考虑以下事项:
Question q = new Blue();
// ... some other code...
q = new Bat(); // Valid!!
q.printName("some string");
现在考虑明天,其他一些开发人员会将其更改为以下内容:
Blue q = new Blue();
// ... some other code...
q = new Bat(); // Invalid!! Compiler error
q.printName("some string");
在操作所需的最高抽象级别声明变量意味着您可以在以后更轻松地更改实现,而不会影响所有其余代码。因此,应该清楚为什么Java编译器将b
视为Question
。这是因为b
可以在任何时候成为Blue
或Bat
的实例,因此将其视为实施(Blue
或Bat
)会违反允许一些其他非arg Question
方法的getName
接口的契约。
答案 1 :(得分:0)
您似乎误解了多态意味着什么。这意味着您可以将派生类的实例视为基类的实例。这包括不调用基类没有提供的方法。变量类型通知您可以调用哪些方法,实例化类型确定运行这些方法的实现。
将Blue
个实例放入Question
变量中,您要求将其视为Question
。如果您想在Question
变量上调用Question
类未提供的方法,那么为什么它会成为Question
变量呢?如果可以在基类变量上调用派生类方法,则它不是基类变量。