java老生常谈问题之RTTI

java老生常谈问题之RTTI

中,我曾经讨论过关于子类和父类之间成员函数的运行时识别的问题,今天要讨论的是成员属性的运行时识别问题。

在我们的印象中java是具有覆盖特性的,但是要注意这个特性仅仅是对成员函数的,对于成员属性可不适用。下面就来小试身手。

package com.whyun.test.rtti;

public class ParentClass {
	public String property = "parent";
	
	public ParentClass() {
		show();
	}
	
	public void show() {
		System.out.println("property in parent:"+property);
	}
}

代码片段1:父类代码

package com.whyun.test.rtti;

public class SubClass extends ParentClass {
	public String property = "sub";

	public SubClass() {
		super();
		show();
	}
	
//	public void show() {
//		System.out.println("property in sub class:"+property);
//	}
	
	public static void main(String[] argc) {
		new SubClass();
	}
}

代码片段2:子类代码

运行一下SubClass这个类,将会输出一下内容:

property in parent:parent
property in parent:parent

也就是说父类方法中的show方法,只会使用父类中的property属性。

接下来,将SubClass中的show方法的注释打开。然后在看一下SubClass的构造函数,构造函数第二行调用show的时候,调用的肯定是他本身的show成员方法;构造函数第一行调用的父类的构造函数,虽然父类的构造函数也是调用的show函数,但是根据RTTI的规则,运行时肯定是调用SubClass中的show成员方法。最终打印的结果如下:

property in sub class:null
property in sub class:sub

由于调用的是SubClass中的show方法,所以打印的字符串的前缀肯定是property in sub class,但是为什么第一打印的时候SubClass的property属性。这个问题可以通过在eclipse中单步跟踪调试来解决。在new SubClass();这行添加断点,然后发现代码首先调用父类构造函数,在调用父类(ParentClass)的构造函数的时候,会先调用ParentClass的父类Object的构造函数,之后初始化ParentClass的成员属性property;然后调用父类构造函数中的show方法,但是这时SubClass的property属性还没有初始化,所以打印出来为null;经过以上操作后ParentClass的构造函数调用完成(也就是super();这句代码执行完成),接着是初始化SubClass的property属性,初始化完成后,最后调用SubClass构造函数中的show();这句代码,由于SubClass的property属性已经初始化,所以将会打印出它的值。

经过以上分析发现,想通过书写同名的成员属性,让子类在运行中覆盖父类的属性,是行不通的,看来需要一种变通的方法。接着看一下代码:

package com.whyun.test.rtti;

public class ParentClass {
	private String property = "parent";
	
	public ParentClass() {
		show();
	}
	
	public ParentClass(String property) {
		this.property = property;
		show();
	}
	
	public void show() {
		System.out.println("property in parent:"+property);
	}
}

代码片段3:修正后的父类代码

package com.whyun.test.rtti;

public class SubClass extends ParentClass {
	private static final String property = "sub";

	public SubClass() {
		super(property);
	}
	
	public SubClass(String myProperty) {
		super(myProperty);
	}

	public static void main(String[] argc) {
		new SubClass();
	}
}

代码片段4:修正后的子类代码

最后运行SubClass类,输出:

property in parent:sub

我们复用了父类的代码,却输出了子类的属性,其实代码不难理解,就是通过调用父类带参数的构造函数,就其属性在构造时动态修改掉,这样使用property这个属性的时候,就是用的子类中的值了。


猜你喜欢

转载自blog.csdn.net/yunnysunny/article/details/7390019