子类覆盖父类的方法与属性后,把子类强制转化为父类类型,为什么这时方法体是子类的,而属性却是父类的呢?
有如下代码可证(呵呵,透露一下,是IBM的面试题,至今我还未解开这个迷,请高手多多指教,不才感激不尽!):
public class FatherClild {
public static void main(String[] are) {
Child c = new Child();
Parent p = c;
System.out.println(p.ParentVar);
System.out.println(p.ParentStaticVar);
System.out.println(p.ParentStaticStr);
System.out.println(c.ParentVar);
System.out.println(c.ParentStaticVar);
System.out.println(c.ParentStaticStr);
p.parentMethod();
p.parentStaticMethod();
c.parentMethod();
c.parentStaticMethod();
}}class Child extends Parent {
public int ParentVar = 15; public static int ParentStaticVar = 14;

//public static String ParentStaticStr = "child";

static {
System.out.println("this is a Child static block");
} public Child() {
System.out.println("this is a Child construct");
} public void parentMethod() {
System.out.println("this is a Child method");
} public int getParentStaticVar() {
return super.ParentVar;
} public static void parentStaticMethod() {
System.out.println("this is a Child static method");
}
}/*
 * 
 */
class Parent {
public int ParentVar = 5; public static int ParentStaticVar = 4; public static String ParentStaticStr = "parent";

static {
System.out.println("this is a parent static block");
} public Parent() {
System.out.println("this is a parent  construct");
} public void parentMethod() {
System.out.println("this is a parent method");
} public static void parentStaticMethod() {
System.out.println("this is a parent static method");
}
}打印的结果是:this is a parent static block
this is a Child static block
this is a parent  construct
this is a Child construct
5
4
parent
15
14
parent
this is a Child method
this is a parent static method
this is a Child method
this is a Child static method通过学习,把我对这些了解的与大家共享一下,望能有更多的交流 1) 类被自动执行的顺序    
静态域(类被加载时)    
静态初始化块(类加载时,当然这时的静态域要先有值,才便于正确执行)    
非静态域(实例开辟内存时)    
非静态初始化块(实例开辟内存时)    
构造方法(实例生成对象引用时)    
2) 当实例化一个第3代的类时,发生的动作将是这样的    
加载第3代,但第3代来源于第2代    
所以加载第2代,但第2代来源于第1代    
所以加载第1代。    
所以:    
(1) 第1代类被加载,发生第1代类加载时的动作(即,静态初始化块)    
(2) 第2代类被加载,发生第2代类加载时的动作    
(3) 第3代类被加载,发生第3代类加载时的动作    
加载完之后,开始创建第3代,但第3代来源于第2代    
所以创建第2代,但第2代来源于第1代    
所以创建第1代    
所以    
(4) 第1代被创建,并初始化,完成该时期的动作(即,非静态初始化块,接着 构造方法)    
(5) 第2代被创建,并初始化,完成该时期的动作    
(6) 第3代被创建,并初始化,完成该时期的动作    
继承父类的理解[]    
从个人理解上看:    
创建父类对象的证据是:子类里都有一个super,它就是父类对象,可见,要创建子类,一定会先创建父类,只是父类做为子类的一个属性(可以这么理解)所以整体上看,是只创建了一个子类。    
简明地说:    
设计者让子类的初始化是首先用父的构造方法来展开的,所以子类在完成造构之前(刚完成调用父类的构造方法展开)父类就实例化了。    
所以我理解了,为什么有的程序只是创建一个对象,却执行了满世界的代码了    
还有一重大发现:    
当父类有多个造构方法时,在子类的构造方法里,可以决定自己是用父类的那个构造方法生成的,所以super()只能用一次,且必须放在构造方法的第一句。    
可见,java在代码复用上下的功夫真不少:    
1) 父类的代码可以供所有的子类使用    
2) 子类在继承父类时,可以选择不同的父类构造方法,得到功能不同的子类(注,只是选择了一个方法,就能达到功能不同,可见代码重用性又提高了)    
注:创建子类时,都会调用父类的构造方法来初始化,系统默认调用无参的父类构造方法。    
若子类的构造方法里,没有指明用父类的构造方法来初始化,则系统自动添加父类的无参构造方法,    
要是此时,父类没有无参的构造方法时,这些将出现编译报错了。(呵呵,编译器还是满厉害的)    
默认情况下,所有的类都有无参构造方法,但自定了构造方法后,系统自带的无参构造方法将不存在,除非再自定义一个无参构造方法  
呵呵,似乎话多了!这是我平常记录的。对我提的问题,我还有一个思路:
      变量的值取决于我们定义的变量的类型,而不是创建的对象的类型,这与编译器是在什么时候(编译、运行)进行匹配的有关系?为什么要分不同的时期匹配?

解决方案 »

  1.   

    override仅仅是说对父类方法的重新定义,与属性无关.
    而且override机制对父类的static/private和final方法无关
    父类的属性只能够隐藏.
      

  2.   

    System.out.println(c.ParentVar);//输出15
            System.out.println(c.ParentStaticVar);//输出14子类的属性输出都是子类的
       何来属性为父类之说??? 
      

  3.   

    "创建父类对象的证据是:子类里都有一个super,它就是父类对象,可见,要创建子类,一定会先创建父类,只是父类做为子类的一个属性(可以这么理解)所以整体上看,是只创建了一个子类。   "调用父类的构造方法,初始化子类从父类继承下来的成员变量
      

  4.   


    倒数第3行 输出:this is a parent static method 不理解...
      

  5.   

    结果应该是这样的吧
    this is a parent static block
    this is a Child static block
    this is a parent  construct
    this is a Child construct
    5
    4
    parent
    15
    14
    child
    this is a Child method
    this is a parent static method
    this is a Child method
    this is a Child static method
      

  6.   

    哦,明白了!
    //public static String ParentStaticStr = "child";
    这句被屏蔽掉了!所以输出的是parent,因为子类继承父类的所有属性和方法。如果去掉这个屏蔽则是子类属性隐藏父类的属性从而输出了child
      

  7.   

    感谢jaywee精辟生动的比喻,让我对父子类方法覆盖的理解顺畅了许多。希望能与您继续讨教这方面的问题。
    1、父子类方法覆盖:我总是想着他们的内存关系,开辟了一个子类空间,用一个父类的句柄来指像它,然后调用的是子类的方法,这可以理解了,因为空间里只有子类的方法。但为什么这时的属性却变成了父亲的属性了呢?不才引用一下您的比喻哦:我买了一辆自行车,方法是骑,属性是自行车的重量。父类就是交通工具了。当我转换为父类时,“把我的交通工具行驶到某处”我的动作是骑自行车。可当人问我“你的交通工具有多重”时,我却不能说自行车的重量呢? 这是我困惑之处。,
      

  8.   

    这样说吧,多态,只有方法才有多态一说,属性是没有这个说法的.
    多态必须满足的条件是:继承,方法的覆盖,以及父类引用指向子类对象.这时候调用的方式是子类的,当然,前提是非static和非private方法.
    属性只有隐藏一说,不可能满足多态的条件.父类的引用,它的类型还是父类的类型,调用的属性还是父类的属性.
      

  9.   

    我不知道我有没有读懂你的意思.但我想,你之所以没法得到自行车的重量,是因为你的设计出现了问题,"重量"这种属性在所有的交通工具里并没有什么共通之处,你可能需要在子类自行车里将重量重新set和get一下.也就是添加"setWeight"和"得到重量(getWeight)"这两个方法.我们这里说的父类属性是说"作为一个交通工具"而应该有的属性,比如有轮子,能行驶,它们是共通的.对于这些共通的属性你当然可以直接使用 父类的.希望我说的可以帮到你.
      

  10.   

    是我没有说清楚,是指这样的        Child c = new Child();
            Parent p = c;
            System.out.println(p.ParentVar);//4
            System.out.println(p.ParentStaticVar);//5p这时虽然是父类的类型,但指向是子类,而输出来的却是父类的值
    所以有“子类输出了父类属性”的嫌疑哦
      

  11.   


    这行对应的代码是:
            p.parentStaticMethod();
    虽然p是指向子类,但parentStaticMethod()是父类的静态方法,而静态方法是在类加载时就决定了,也就是编
    译器在编译的时候,就根据p的类型为Parent给了p的Parent.parentStaticMethod()方法。
    也就是说静态方法只与对象的类型有关。
      

  12.   

    抱歉,刚刚点错了这个问题其实理解起来不难,如果明确了继承的概念就很好理解了,子类继承了父类的所有东西(注意,访问控制可能会使你不能访问父类对象里的一些属性),这点楼主也说到了,这就好办了. 
    当你把子类对象看成一个父类对象的时候(这个没有任何问题upcasting当然是安全的),子类对象里的属性,对外界来说,是看不到的,也就是说把子类对象里的属性给"咔嚓"掉了,外界只能看到父类对象里的属性,你取得的也只能是父类对象的属性值,这个并不是覆盖不覆盖的问题不知道这样子说,你能想清楚不?
      

  13.   

    Parent p = c;
    关键在于这一句~P是用父类定义的父类对象!~然后你再把子类对象赋给父类对象!~这个情况你只要去查一下C#中类的继续这一章就会有详细的说明的!~
      

  14.   

    我也来问个问题:
    父类 A(这是一个基类窗体:form)
    子类 b,c,d(子类窗体:mdiform)Form frm = this.ActiveMdiChild;
    (A)frm.方法这是将子类强制转换为父类,执行的方法,在A里面是虚方法,在子窗体中重写了该方法,这样对于不同的子窗体,就能执行不同的方法
    这样做算不算多态?如果不算,和多态有什么区别?多态的应该是:
    A a=new b();
    a.方法