最近在学习JAVA,看到书中有说:可以将子类的对象赋给父类的引用,但是在运行时,通过RTTI来判断引用所代表的是子类的对象还是父类的对象,并且能够正确地识别所调用的方法。那么按照这样的理解,下面的代码:
class A {
    public boolean flag = false;
    
    public void Show() {
        System.out.println("From A");
    }
}class B extends A {
    public boolean flag = true;
    
    public void Show() {
        System.out.println("From B");
    }
}public class Test {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        A c = b;
        
        System.out.println(a.flag);
        System.out.println(b.flag);
        System.out.println(c.flag);
        
        a.Show();
        b.Show();
        c.Show();
    }
}
这个代码的运行结果应该是:
false
true
true
From A
From B
From B
可是在实际的运行结果却是:
false
true
false
From A
From B
From B
请问这个是什么原因呢。

解决方案 »

  1.   

    field和方法不一样.
    方法的问题就是根据你开头那段话来确定的.
    field没有这个问题.
      

  2.   

    class A {
        public boolean flag = false;    public void Show() {
            System.out.println("From A");
        }
        public boolean getflag(){
         return flag;
        }
    }class B extends A {
        public boolean flag = true;    public void Show() {
            System.out.println("From B");
        }
        public boolean getflag(){
         return flag;
        }
        public boolean getsuperflag(){
         return super.flag;
        }
    }public class test {
        public static void main(String[] args) {
            A a = new A();
            B b = new B();
            A c = new B();        System.out.println("*******************flag*********************");
            System.out.println(a.flag);
            System.out.println(b.flag);
            System.out.println(c.flag);
            System.out.println("*****************getflag()******************");
            System.out.println(a.getflag());
            System.out.println(b.flag);
            System.out.println(c.getflag());
    //      System.out.println(c.getsuperflag());        a.Show();
            b.Show();
            c.Show();
        }
    }
    我把楼主的代码改了一下,当我要加上System.out.println(c.getsuperflag());这句话时提示 A型没有定义。
    说明实例c虽然是通过B创建的但C还是A类型。而且类继承时如果有相同名变量,子类中不会被覆盖,只是在子类中加super.
    像楼主那样定义,用c.flag进行调用时,其实是调用A的flag
    这是我的理解,有些词可能用的不对,我只是想表达个意思。请见谅
      

  3.   

    首先感谢 chensi3344 的回复,你的代码的运行结果如下: 
    *******************flag*********************
    false
    true
    false
    *****************getflag()******************
    false
    true
    true
    From A
    From B
    From B这里我注意到:如果我直接去引用字段的话,如c.flag。则显示的是 false,若我去引用方法的话,如 c.getflag()。则显示的是true。这里的一个区别是:一个是引用所代表的类型的值,一个是赋给引用的对象的类型的值。这个是关键点。就是说为什么字段和方法的覆盖会不同呢?
      

  4.   


    class A { 
        public boolean flag = false; 
        
        public void Show() { 
            System.out.println("From A"); 
        }
        public boolean flagChange(){
         return flag;
        }
    } class B extends A { 
        public boolean flag = true; 
        
        public void Show() { 
            System.out.println("From B"); 
        } 
        
        public boolean flagChange(){
        
         return this.flag;
        }
    } public class Test { 
        public static void main(String[] args) { 
            A a = new A(); 
            B b = new B(); 
            A c = new B(); 
         
           
            
            System.out.println(a.flag); 
            System.out.println(b.flag); 
            System.out.println(c.flag);
            System.out.println(c.flagChange());
            
            a.Show(); 
            b.Show(); 
            c.Show(); 
        } 
    } /* output:false
    true
    false
    true
    From A
    From B
    From B
      

  5.   


    B类
    {
       public boolean super.flag = false;   //A
       public boolean flag = ture;          //B
       public void Show() {
            System.out.println("From B");
        }
        public boolean getflag(){
            return flag;
        }
        public boolean getsuperflag(){
            return super.flag;
        }
    }c是A类型,当c用B去创建时                 c.flag 应该是  super.flag
             getflag()被重写了           c.getflag() 应该是  flag
    不知道你看懂了吗?我表达可能不清。
      

  6.   


    c
    {
       public boolean super.flag = false;   //A
       public void Show() {
            System.out.println("From B");
        }
        public boolean getflag(){
            return flag;                    //B中flag
        }
    }
    在上溯的过程中,接口变窄了,它本身的一些方法(例 getsuperflag())就不可见了。
      

  7.   

    父引用是可以装子对象
    1:当父引用(装子对象).子类独有方法  ---------------编译错误 因为javac 时,JVM会先检查你父类有无此方法,如果                                                    没有就报错,而后考虑父引用装的是不是子对象2:当父引用(装子对象).子类重写父member方法 --------这时调的是子类的重写方法。
    3:当父引用(装子对象).子类重写父static方法 --------这时调的是父类的方法。
    3:当父引用(装子对象).属性(不管static和member属性) --------这时调的是父类的属性。
      

  8.   

    A c = b;
    不是声明c是A类吗 ,A c = b————只是说明给c赋初值,即给定一个存储地址,但c作为一个A类其方法和变量都不变。
      

  9.   

    今天光这问题就看到3个,我去拉段解释来~
    java中有两种绑定,静态绑定和动态绑定。变量用的是静态绑定,就是说在编译的时候已经绑定好了。而方法是在运行时去绑定的。换句话说就是在.java文件编译成.class文件的时候变量的值已经定死了。所以sup.field等于0。
    静态绑定:变量和静态方法。
    动态绑定:实例方法。
      

  10.   

     基本同意你的解释,这个应该是Java静态绑定与多态型的经典体现,楼主的Flag 是变量只能根据声明的引用来获取超类的变量值。