这难道是Java多态的性质

这难道是Java多态的本质?
本帖最后由 BeyondYaphetS 于 2014-06-06 16:20:28 编辑
今天在回顾File,InputStream,OutputStream,Reader,Writer的时候,回顾了一下Java的多态,发现这样一个问题。
比如有以下继承关系类:
class A{
   public int a;
   public void funcA();
}
class B extends A{
    public int b;
    public void funcA();
    public void funcB();
}
class C extends A{
   public int c;
   public void funcA();
   public void funcC();
}
A a1 = new A();
A a2 = new B();
A a3 = new C();
下面说说我的个人理解:
a2.funcA()调用的是B中重写的方法
a3.funcA()调用的是C中重写的方法
a2.b会报错
同样a3.c也会报错。
是不是可以这样理解, a2,a3是A类型的对象,其实是引用类型,本质就是一个指针,将B,C的对象直接赋值给A类的对象,也就是子类赋给父类,这种赋值可以允许,可以成功,这一现象才是Java多态机制的根源本质,我是这样理解的,先不管他怎么个继承法,是继承谁,你B的对象的地址可以赋值给我A类型的对象指针,那你B,C中新增的部分,赋值的时候被砍掉了,B,C中重写的部分,赋值的时候把A中原来的覆盖了,那我用A的对象去调用的时候就得调用到符合我A模样的方法和变量,
也就是a2,a3,可以调用到被B,C重写的,和A中原来的,但是调用不到B,C中新增的原因。从而导致用父类对象调用同一个方法的时候可以分别调用到被各个子类重写的方法,从而实现多态。以上是一些个人理解。。。
请谈谈你们的看法,交流一下,谢谢!!



------解决方案--------------------
A a2 = new B()

int i = 10000000;
byte b = (byte) i;
这样的“转换”是不一样的,后者直接把多余的数据舍弃了(int多余的3个字节转换以后就没了)

前者的意思只是,创建一个新的B实例,然后告诉编译器它是A类型的,并不存在任何“转换”,所以你说的B中新增的部分被砍掉了肯定是不对的,这点你可以把它再转换为B类型验证

如果存在重写,那么子类初始化的时候就会覆盖父类原来那个方法,所以你调用a2.funcA()是调用子类的方法

而a2.b是编译期错误,因为你告诉编译器a2是A类型,那么编译器就认为它不存在b这个成员变量,你这样访问编译器肯定不允许,即便这个成员是存在的。

------解决方案--------------------
这个是多态的特性之一,原因是因为后期绑定(意思就是运行时根据对象的类型进行绑定),比如:
A a2 = new B();    //运行是自动绑定成A
A a3 = new C();  //同理
这在面向对象语言里面叫做向上转型。向上转型之后可以拥有父类所有非私有方法和属性,但自身的一些父类没有的方法或属性会被阉割掉,这就是为什么你说
a2.b会报错
同样a3.c也会报错。
如果要让a2.b,a3.c正常执行,有两种方法:一种是不使用向上转型,即直接 B a2 = new B();  //地球人都知道
另一种是使用向下转型,即把已经向上转型的数据类型强制向下转型,如
A a2 = new B();  
(B)a2.b   //编译不报错