public class TestExtend1 { 
public static void main(String[] args) { 
A a = new B(); 
a.method1(); 
a.method2(); 
System.out.println("i = " + a.i); B b = new B(); 
b.method1(); 
b.method2(); 
b.method3(); 
System.out.println("i = " + b.i); 

} class A { 
public int i = 0; 
public void method1(){System.out.println("A's method1");} 
public void method2(){System.out.println("A's method2");} 
} class B extends A { 
public int i = 1; 
public void method2(){System.out.println("B's method2");} 
public void method3(){System.out.println("B's method3");} 
} ------------------------------------------------------------------- 
输出结果: 
A's method1 
B's method2 
i = 0 A's method1 
B's method2 
B's method3 
i = 1 
-------------------------------------------------------------------- 
问题: 
1.关于继承,通过此题的结果可以看出B重写了A的method2(),也"重写"了A的属性i,但是为什么A a = new B()的a.i还是访问了A类的a=0呢?这个问题困惑了好久希望能够得到详细的答复,本人看了一些java的视频教程,但是经典的java书籍没时间看,导致这些方面的问题不懂. 
2.对A a = new B()还是理解不深,怎么a是获得了B类的对象,但是a还是不能调用在B类有A类没有的方法method3()呢?详细解释一下A a = new B(); 
3.在笔试的时候经常撞到一些static和继承的混合考点,题型多数是看程序写出结果,在网上找得不多,希望能补充一些习题以加深记忆. 

解决方案 »

  1.   

    我昨天问了下老师关于A a=new B();的这个问题,后来我搞明白了,,这里是父类指向子类的对象,一个向上转类\型的过程,但是a还是类A的一个实力化,所以这里你的A a=new B();里面的a是只能调a只能访问a里面的方法和属性,而无法访问B类的属性和方法.所以这里的a.i=0;
    关于A a=new B();的作用,,基本就用在多态上面了.
    例如:public class Shape
    {
    public void draw()
    {
    System.out.println("绘制图形");
    }
    }
    public class Circle extends Shape
    {
    public void draw()
    {
    System.out.println("绘制圆形");
    }
    }
    public class Triangle extends Shape
    {
    public void draw()
    {
    System.out.println("绘制三角形");
    }
    }
    public class Square extends Shape
    {
    public void draw()
    {
    System.out.println("绘制正方形");
    }
    }
    public class Test
    {
    public void draw(Shape s)
    {
    System.out.println("绘制正方形");
    }
    public static void main(String []args)
    {
    Test t=new Test();
                    t.draw(new Square());
    }
    }个人理解喔..父类指向子类这种实力化大多数是用在多态上面的..这样的话,你不至于每要绘制一个图形都更改test类里面的draw()方法了,其实你也可以把draw()方法里面的参数类型直接改成子类的,那么你只要添加一个子类的话,你就要在test类里面重新添加一个draw()方法了,这里main方法里面其实就相当与是Shape s=new Square();了..我也是半懂不懂..说的如果有错误请高手们改正,虚心学习中.!
      

  2.   

    我昨天问了下老师关于A a=new B();的这个问题,后来我搞明白了,,这里是父类指向子类的对象,一个向上转类\型的过程,但是a还是类A的一个实力化,所以这里你的A a=new B();里面的a是只能调a只能访问a里面的方法和属性,而无法访问B类的属性和方法.所以这里的a.i=0;
    关于A a=new B();的作用,,基本就用在多态上面了.
    例如:public class Shape
    {
    public void draw()
    {
    System.out.println("绘制图形");
    }
    }
    public class Circle extends Shape
    {
    public void draw()
    {
    System.out.println("绘制圆形");
    }
    }
    public class Triangle extends Shape
    {
    public void draw()
    {
    System.out.println("绘制三角形");
    }
    }
    public class Square extends Shape
    {
    public void draw()
    {
    System.out.println("绘制正方形");
    }
    }
    public class Test
    {
    public void draw(Shape s)
    {
    System.out.println("绘制正方形");
    }
    public static void main(String []args)
    {
    Test t=new Test();
                    t.draw(new Square());
    }
    }个人理解喔..父类指向子类这种实力化大多数是用在多态上面的..这样的话,你不至于每要绘制一个图形都更改test类里面的draw()方法了,其实你也可以把draw()方法里面的参数类型直接改成子类的,那么你只要添加一个子类的话,你就要在test类里面重新添加一个draw()方法了,这里main方法里面其实就相当与是Shape s=new Square();了..我也是半懂不懂..说的如果有错误请高手们改正,虚心学习中.!
      

  3.   

    多System.out.Println(),把信息都打出来,看看执行顺序就OK了,慢慢就懂了
      

  4.   

    1.我的理解,第一题应该为类的属性是前期绑定,而方法是后期绑定。
    2.A a = new B() 这一句,是A类型的引用指向了被new出来的B类型的对象。
    a不能调用B的method3(),因为编译期还不知道 a 其实是B类型的对象。
    所以你要强制的转换类型,((B)a).method3().
    3.把基础搞好,不要搞那么多题,题型很多,而且在变,但java的规范没有变。
      

  5.   

    加红色的部分有点绕。
    a还是类A的一个实力化?
    a指向了B类型的一个对象,只是B是类A的子类而已,所以可以这样向上转型。
    在构造B的时候,确实是去 “实例化” 了A,但并没有 类A的对象存在,只有类B的这个被new出来的对象而已。
    这里的实例化,只是把父类A中的属性实例化了,调用了类A的构造方法。里面的a是只能调a只能访问a里面的方法和属性,而无法访问B类的属性和方法.?
    这句话已经被你的例子打破了啊。
    执行 a.method2(); 后的结果是什么,其实已经访问了B类的方法啊。
    因为后期绑定啊。
    a.i确实不能访问到类B的i。
    你可以参考下think in java的相关内容。
    在执行一个方法的时候,其实除了方法显示的参数以外,还有默认的参数也被传入了。(并不严谨,望指正)
    就是指向自己的this,和指向父类区域的super。
    如果在this中没有,则去super中找。
    所以,
    a.method1(); 输出 类A的方法
    a.method2(); 输出类 B的方法。
      

  6.   

    1、子类可以重写父类里所有不是final的属性和方法(private的属性和方法严格来说不算重写),包括static的。
    对于这些被重写的属性和方法,都保存在内存中。当使用它们的时候,具体使用哪一个版本的,根据对象引用标识符的类型而定。2、对于一个父类的引用标识符,它到底是指向一个父类的对象还是子类的对象或者指向哪个子类的对象,只有到运行的时候才能确定,在编译的时候编译器并不知道父类的引用标识符指向谁。对于父类的应用标识符指向一个子类的情况,编译器完全将它作为父类的对象,所以对B b = new B();
    A a = b;的情况,虽然a、b指向同一个对象,但是它们可以调用的方法是不同的。b不能调用A类的private属性和方法,而a不能调用B类的所有属性和方法。虽然a实际指向一个B类的对象,但是它还是可以调用A类的private方法。
    3、和上面一样,static的所有东西是不能继承的,但是可以用同样的方法签名写一个新的方法。运行的时候调用哪个版本的方法由引用操作符的类型而定。
      

  7.   

    谢谢这位大哥纠正..我再回味下..那上面的只是我之前的理解.肯定有些错误的,我才学java不久.对于这位大哥的耐心指点,真的感激不尽..谢谢
      

  8.   

    public class TestExtend1 { 

    public static void _print(A a)
    {
    a.method2();
    }
    public static void main(String[] args) { 
    A a = new B(); 
    a.method1(); 
    a.method2(); 
    _print(a);
    System.out.println("i = " + a.i); B b = new B(); 
    b.method1(); 
    b.method2(); 
    b.method3(); 
    _print(b);
    System.out.println("i = " + b.i); 

    } class A { 
    public int i = 0; 
    public void method1(){System.out.println("A's method1");} 
    public void method2(){System.out.println("A's method2");} 
    } class B extends A { 
    public int i = 1; 
    public void method2(){System.out.println("B's method2");} 
    public void method3(){System.out.println("B's method3");} 
    }
    ======
    A's method1
    B's method2
    B's method2
    i = 0
    A's method1
    B's method2
    B's method3
    B's method2
    i = 1
    楼主看下红色部分的代码,我新加上去的,它们调用了方法_printf(); 其中有参数A ,子类的对象可以传递给A的对象a(自动转换),父类引用的对象可以调用不是父类中定义的方法,那是多态的特点。因为多态是通过动态绑定实现的。就如这段代码:
    B b = new B(); 
    _print(b);
    虽然是通过A类的对象引用调用的方法,但是这个对象引用指向实际类型是其子类的对象,因此,通过它调用的就是其相应的子类中的方法。
      

  9.   

    这不是继承问题,是动态绑定。动态绑定的条件:要有继承;要有重写;父类引用指向其子类对象。符合这三个条件就是动态绑定。a.i访问了A类的i=0,是因为a的类型是父类a。当你用A a=new B()时,你只能调用B重写了A的方法和A的方法(A有B没有)及A的变量。还是那句话,a的类型是A。如果a的类型是B,那么B的方法都可以调用,A的方法无论有没有被重写都可以调用。
      

  10.   

    大家讨论的都差不多了,
    我只是补充一点:
    JAVA的内存处理机制,其实,A a = New B();是声明了一个引用对象,该对象的类型是A,但他在实际指向的时候指向了B的一个对象,之所以可以如此,是因为,A B之间的继承关系,他们可以包含。
      

  11.   

    new B();
    归根到底他是B啊。一切方法的执行结果要以B为准
    举个例子
    人是父类
    子类有张三、李四
    人有个说话的方法,实现就一行代码,出声。
    张三和李四都能说话,但是说话声音肯定是不同的。
    你做了个张三,把他叫来,尽管你看不见他,只知道他是个人,你让他说话,他说话的声音还是张三。还是可以分辨。就这么简单,你new个什么对象出来,无论强转成什么,调用方法的时候也成不了别的。
      

  12.   

    1.为什么A a = new B()的a.i还是访问了A类的a=0呢?继承所带来的有成员的覆盖和隐藏。
    有下面三点:第一点是实例方法的覆盖,我相信这个你已经知道了,我就不说了,注意实例方法是不带static的;
    第二点是字段的隐藏,这个你不清楚,子类是不能覆盖超类(父类)的字段,可以定义相同名字的字段。也就是说如果你定义了个相同名字的字段在子类中,那么父类的那个相同名字的字段子类就不管了,也就是隐藏起来了。所以a.i是a自己的i属性。
    第三点是静态方法的隐藏,跟字段差不多。
    教你个方法,A a = new B();当利用引用调用实例方法的时候,你要看引用所代表当前对象的类决定了执行哪一种方法的实现;
    而调用字段或者静态方法的时候,你要看引用的类型(不是引用所代表当前对象的类)。
    有点绕口,多看例子。
    2.A a = new B();就是父类引用指向了子类对象。一个子类对象的属性和方法是比父类多的,在内存中相当于一个大正方形包着一个小正方形,大的是子类,小的是父类。当父类引用A a 指向了new B()时,实际上就是把B看做了A,可以想象成指向了小正方形,但调用他的方法的时候要注意一些细节,也就是是否被覆盖了。
    3.
    public class Test {
    public static void main(String []args){
    A a = new B();//a是A引用类型,代表的是类B
    B b = new B();
    System.out.println(a.ii);//打印出a自己的ii.(调用字段或者静态方法的时候,你要看引用的类型(不是引用所代表当前对象的类))
    System.out.println(b.ii);
    a.method1();//执行a自己的method1.(调用字段或者静态方法的时候,你要看引用的类型(不是引用所代表当前对象的类))
    b.method1();
    a.method2();//执行b的method2,method2是实例方法
    b.method2();
    }}
    class A{
    public int ii=1;
    public static void method1(){
    System.out.println("A:static method");
    }
    public void method2(){
    System.out.println("A:not static method");
    }
    }
    class B extends A{
    public int ii =2;
    public static void method1(){
    System.out.println("B:static method");
    }
    public void method2(){
    System.out.println("B:not static method");
    }
    }