Java 编译时非多态
Java Compile time non polymorphism
在下面的代码中,我在 b.printname(); 处遇到编译器错误。据我了解,错误与编译器以非多态方式有效运行的事实有关(即编译器基本上只选择查看操作数的左侧,因此 b 是一个问题)。由于 b 是 Question 类型,并且 Question 没有无参数的 printName 方法,因此您会遇到编译错误。那是对的吗?
现在假设这是正确的,我的问题是为什么?编译器当然应该知道问题 b 指的是一个实际上支持无参数 printName 方法的对象?例如。如果您查看编译器在强制转换方面的行为,有一些示例,其中编译器由于缺少更好的词而以多态方式运行,或者换一种方式编译器知道在右侧发生了什么操作数并根据该知识采取行动。一个例子是,如果一个接口类型引用一个实现该接口的对象,那么编译器会查看语句的右侧(即实现该接口的对象)并决定不需要强制转换。那么,为什么编译器在这里不那样做,为什么它不查看并看到所讨论的对象实际上是一个 Blue,而 Blue 确实支持无参数方法 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);}
}
}
虽然 b
是 Blue
类型,但由于您将其声明为 Question b = new Blue();
,编译器将其视为 Question
类型,因此这是唯一可用的接口没有明确的强制转换:
((Blue)b).printName();
或者,您可以将其声明为 Blue b = new Blue();
并且 b.printName();
不会抛出编译时错误。
基本上这里发生的是你在更高的抽象层次上声明你的新变量 b
,所以 b
唯一可用的 printName
方法是更高级别的抽象,具有 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
)将违反Question
接口的契约通过允许一些其他非参数 getName
方法。
你好像误解了多态的意思。这意味着您可以将派生 class 的实例视为基础 class 的实例。这包括不调用基础 class 不提供的方法。变量类型通知您可以调用哪些方法,实例化类型确定这些方法的实现是什么 运行.
通过将 Blue
实例放入 Question
变量中,您要求将其视为 Question
。如果您想在 Question
变量上调用 Question
class 未提供的方法,那么为什么要使用 Question
变量呢?如果您可以在基本 class 变量上调用派生-class 方法,则它不会是基本 class 变量。
在下面的代码中,我在 b.printname(); 处遇到编译器错误。据我了解,错误与编译器以非多态方式有效运行的事实有关(即编译器基本上只选择查看操作数的左侧,因此 b 是一个问题)。由于 b 是 Question 类型,并且 Question 没有无参数的 printName 方法,因此您会遇到编译错误。那是对的吗? 现在假设这是正确的,我的问题是为什么?编译器当然应该知道问题 b 指的是一个实际上支持无参数 printName 方法的对象?例如。如果您查看编译器在强制转换方面的行为,有一些示例,其中编译器由于缺少更好的词而以多态方式运行,或者换一种方式编译器知道在右侧发生了什么操作数并根据该知识采取行动。一个例子是,如果一个接口类型引用一个实现该接口的对象,那么编译器会查看语句的右侧(即实现该接口的对象)并决定不需要强制转换。那么,为什么编译器在这里不那样做,为什么它不查看并看到所讨论的对象实际上是一个 Blue,而 Blue 确实支持无参数方法 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);}
}
}
虽然 b
是 Blue
类型,但由于您将其声明为 Question b = new Blue();
,编译器将其视为 Question
类型,因此这是唯一可用的接口没有明确的强制转换:
((Blue)b).printName();
或者,您可以将其声明为 Blue b = new Blue();
并且 b.printName();
不会抛出编译时错误。
基本上这里发生的是你在更高的抽象层次上声明你的新变量 b
,所以 b
唯一可用的 printName
方法是更高级别的抽象,具有 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
)将违反Question
接口的契约通过允许一些其他非参数 getName
方法。
你好像误解了多态的意思。这意味着您可以将派生 class 的实例视为基础 class 的实例。这包括不调用基础 class 不提供的方法。变量类型通知您可以调用哪些方法,实例化类型确定这些方法的实现是什么 运行.
通过将 Blue
实例放入 Question
变量中,您要求将其视为 Question
。如果您想在 Question
变量上调用 Question
class 未提供的方法,那么为什么要使用 Question
变量呢?如果您可以在基本 class 变量上调用派生-class 方法,则它不会是基本 class 变量。