Java访谈后的反思:继承和多态性
以下代码:Java访谈后的反思:继承和多态性,java,inheritance,polymorphism,Java,Inheritance,Polymorphism,以下代码: class Base{} class Agg extends Base{ public String getFields(){ String name="Agg"; return name; } } public class Avf{ public static void main(String args[]){ Base a=new Agg(); //please take a look here System.out.pr
class Base{}
class Agg extends Base{
public String getFields(){
String name="Agg";
return name;
}
}
public class Avf{
public static void main(String args[]){
Base a=new Agg();
//please take a look here
System.out.println(((Agg)a).getFields()); // why a needs cast to Agg?
}
}
我的问题是:为什么我们不能将((Agg)a).getFields()
替换为a.getFields()
?为什么我们需要在a
上键入cast?我提到getFields()
没有在类Base
中定义,因此类Agg
没有从其基类扩展此方法。但如果我在类Base
中定义了方法getFields(),
比如:
一切都会好的。然后
((Agg)a).getFields()等同于a.getFields()
在代码中
Base a=new Agg();
此行是否意味着a
引用了Agg()
,并且a可以直接调用classAgg
的方法。但是如果我不在类Base
中定义方法getFields()
,为什么会有区别呢?谁能给我解释一下吗
System.out.println(((Agg)a.getFields());//为什么a需要转换为Agg?
因为Base
没有名为getFields
的方法
宣言
Base a;
…告诉编译器在使用a
时要使用的接口。然后分配newagg()并不重要
对于它,您必须a
的界面仍然是Base
。由于Base
没有getFields
,因此尝试使用getFields
是一个编译错误
Base a=new Agg()代码>
此行是否意味着a
引用了Agg()
,并且a可以直接调用classAgg
的方法
这意味着a
包含对Agg
对象的引用,但是该对象的接口是由Base
定义的,而不是Agg
,因此如果Agg
方法不是由Base
定义的,则不能对其调用Agg
方法(没有强制转换,强制转换是危险的,应该尽可能避免)
如果代码需要访问由Agg
定义的方法或字段,那么变量(或参数,在我的示例中)应该声明为Agg a
,而不是Base a
这是OOP的基本原理,尤其是Java中的OOP实现:对象的接口和对象的实现之间有很大的区别。在您的示例中,您知道基础A < /C> >实际上是<代码> AGG,但请考虑如下:
void foo(Base a) {
// Use `a` here...
}
// A long time later in a class far, far away...
xyz.foo(new Agg());
显然,在这里,编译器不应该允许您在a
上使用未由Base
定义的方法或字段。代码中的情况也一样,只是不太明显
System.out.println(((Agg)a.getFields());//为什么a需要转换为Agg?
因为Base
没有名为getFields
的方法
宣言
Base a;
…告诉编译器在使用a
时要使用的接口。然后分配newagg()并不重要
对于它,您必须a
的界面仍然是Base
。由于Base
没有getFields
,因此尝试使用getFields
是一个编译错误
Base a=new Agg()代码>
此行是否意味着a
引用了Agg()
,并且a可以直接调用classAgg
的方法
这意味着a
包含对Agg
对象的引用,但是该对象的接口是由Base
定义的,而不是Agg
,因此如果Agg
方法不是由Base
定义的,则不能对其调用Agg
方法(没有强制转换,强制转换是危险的,应该尽可能避免)
如果代码需要访问由Agg
定义的方法或字段,那么变量(或参数,在我的示例中)应该声明为Agg a
,而不是Base a
这是OOP的基本原理,尤其是Java中的OOP实现:对象的接口和对象的实现之间有很大的区别。在您的示例中,您知道基础A < /C> >实际上是<代码> AGG,但请考虑如下:
void foo(Base a) {
// Use `a` here...
}
// A long time later in a class far, far away...
xyz.foo(new Agg());
显然,在这里,编译器不应该允许您在a
上使用未由Base
定义的方法或字段。代码中的情况也一样,只是不太明显
我的问题是:为什么我们不能将((Agg)a.getFields()替换为a.getFields()?为什么我们需要在一个屏幕上打字
听起来您真的理解了这一点-编译器在编译时类型a
(即Base
)上找不到getFields
方法,因此它会引发编译时错误
这似乎是问题的真正含义:
Base a=new Agg();
此行是否意味着a具有Agg()的引用,并且a可以直接调用类Agg的方法。但如果我不在基类中定义getFields()方法,为什么会有区别呢?谁能给我解释一下吗
这意味着编译器只允许您访问Base
的成员,因为它只知道这些成员是可用的。如果有多个方法具有相同的名称,则重载解析也将应用于编译时类型
但是,在执行时,您实际上是在调用类型为Agg
的对象上的方法-因此,如果Agg
覆盖在Base
中声明的方法,则将使用Agg
中的实现
基本上,您需要区分在编译时根据表达式的编译时类型做出的决策和(由JVM)在执行时根据值引用的对象的执行时类型做出的决策
我的问题是:为什么我们不能将((Agg)a.getFields()替换为a.getFields()?为什么我们需要在一个屏幕上打字
它变臭了