Java中父类和子类中的方法调用和参数传递总结

有这样一段程序,看看它会输出什么结果

代码装载自:http://blog.csdn.net/xiaokang123456kao/article/details/75195045
public class Test {  
    public static void main(String [] args){  
        System.out.println(new B().getValue());  
    }  
    static class A{  
        protected int value;  
        public A(int v) {  
            setValue(v);  
        }  
        public void setValue(int value){  
            this.value = value;  
        }  
        public int getValue(){  
            try{  
                value++;  
                return value;  
            } catch(Exception e){  
                System.out.println(e.toString());  
            } finally {  
                this.setValue(value);  
                System.out.println(value);  
            }  
            return value;  
        }  
    }  
    static class B extends A{  
        public B() {  
            super(5);  
            setValue(getValue() - 3);  
        }  
        public void setValue(int value){  
            super.setValue(2 * value);  
        }  
    }  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

输出:

22
34
17
  • 1
  • 2
  • 3

这段程序咋一看没什么特殊的,但是细细分析下来,发现想搞清楚它的运行过程还真不简单。通过Eclipse单步调试,得出其运行流程如下:(序号1、2就表示运行次序)


public class Test {
    public static void main(String[] args) {
        System.out.println(new B().getValue());//1、程序开始
    }

    static class A {
        protected int value;//

        public A(int v) {//4、调用A的构造方法,v=5
            setValue(v);//5、调用setValue方法(关键是调用A中的方法还是B中的?)
            /*
             * 这其实涉及到编译时类型和运行时类型的问题,就setValue(v);这条语句而言,
             * 调用这条语句的对象实际上是this。而this的编译时类型是A(编译时这条语句在A类中),
             * 但是运行时类型却是B。main方法中只有一条语句,我们分析的所有操作都是因为
             * new B().getValue()这个语句引起的。所以运行时类的类型是B。那么我们调用的自然
             * 是B中的setValue方法。只有当B中没有setValue方法时,才会调用父类A中的setValue方法。
             */
        }

        public void setValue(int value) {//8、子类B通过super显示调用该方法,输入参数value=10
            this.value = value;//9、与第5步类似,这里this还是指B类,但是B类中并没有显式定义名为value的成员,但是因为B类继承了A,
            //而A中的value修饰符为protect,所以B类也继承了这个value成员。而且,这时A,B中持有的value引用是一样的,是指向同一内存区域。
            //换句话说,无论两者谁修改了value的值,都会影响到对方。
            //this.value=value是把B类中value值设为10,同时A中的value值受到影响,也变为10(因为是同一个value引用)
        }

        public int getValue() {//11、执行getValue方法,此时A的成员变量value值为10
            try {
                value++;//12、A的value值变为11,同时B中的value值变为11
                return value;//13、返回value=11,但不会立即返回,会先执行finally语句块
            } catch (Exception e) {
                System.out.println(e.toString());
            } finally {//14、finally语句块
                this.setValue(value);//15、调用B的setValue方法
                System.out.println(value);//16、输出value值,此时A(B)中的value为22
                /*
                 * finally语句块执行完毕后会执行try语句块中的return语句,虽然value的值变为22,但是getValue()的返回值仍然是11。
                 * 这是因为在try语句块中的return语句执行时把返回值保存在局部变量里,需要返回时再取出来。
                 * 但是假如在finally语句中也有return语句的话,返回值就是finally语句块中的return返回值,而try语句块中的返回值被覆盖(失效)
                 */
            }
            return value;//不会执行该句
        }
    }

    static class B extends A {
        public B() {//2、先调用B的构造方法
            super(5);//3、调用父类A的构造方法并传入参数5
            setValue(getValue() - 3);//10、执行该句,首先计算getValue() - 3的值,这将调用A的getValue()方法。
            //11、计算得到getValue() - 3=8,然后执行setValue(8),
        }

        public void setValue(int value) {//6、调用子类的setValue方法
            super.setValue(2 * value);//7、通过super显式调用父类的setValue方法,传入参数10
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

通过对上述程序的分析,可以得到如下信息: 
1、当子类对象调用一个方法时,会优先在子类中查找,然后才回去父类中查找。如果子类调用了父类的方法method1,而method1又调用了method2,那么这个method2还是会优先在子类中查找,找不到才会去父类中查找。 
2、如果子类继承了父类的成员变量(前提是可以继承public和protected),而子类没有显示覆盖该成员变量,那么子类访问到的成员变量和父类访问到的成员变量是同一个变量。任何一个修改后都会影响到另一个。 
3、try中的return会在finally语句块之后运行,如果finally语句块中有return语句,那个就直接返回这个return值。如果没有,就返回try中的return值(finally块中的任何非return操作都不会影响到try中的return值)。、


个人总结:

为什么会有3个输出

1.new B().getValue()有两个输出

new B(),首先调用父类构造函数,在调用自己的构造函数。会输出一次System.out.println(value);

getValue()时会调用A的getValue()函数,输出一次System.out.println(value);

2.System.out.println(new B().getValue())会输出一次

执行完new B().getValue(),会return一个value=17

猜你喜欢

转载自blog.csdn.net/fle123/article/details/78357143