构造中的多态

各位仁兄,前几日我在项目中写了类似这么一段代码

 

AbstractClass

package com.my.study;

public abstract class AbstractClass {
	private final Object comm;

	protected AbstractClass(Object comm) {
		super();
		this.comm = comm;
		this.buidSelf();
		this.buildChildren();
	}
	public Object comm(){
		return this.comm;
	}
	protected abstract void buidSelf();
	protected abstract void buildChildren();
	

}

 TestClass

package com.my.study;

public class TestClass extends AbstractClass {

	public TestClass(Object o) {
		super(o);
	}

	@Override
	protected void buidSelf() {
		System.out.println("buildSelf");

	}

	@Override
	protected void buildChildren() {
		System.out.println("buildChildren");

	}

	public static void main(String g[]) {
		new TestClass(new Object());
	}
}

 看看这代码 有什么问题呢?不管三七二十一,先跑跑看,结果如图

 



一切ok,没问题

 

但究竟有什么问题呢?请看以下代码

 

package com.my.study;

public class TestClass extends AbstractClass {

	private Object a=null;
	public TestClass(Object o) {
		super(o);
		
	}
	public void run(){
		System.out.println(a.toString());
	}
	@Override
	protected void buidSelf() {
		System.out.println("buildSelf");

	}

	@Override
	protected void buildChildren() {
		System.out.println("buildChildren");
		a=new Object();

	}

	public static void main(String g[]) {
		new TestClass(new Object()).run();
	}
}
 

再运行一下,结果如下图

 

 



 怎么回事,为啥会有exception?不是给它赋值了吗?Why?

 

可以明确的告诉你,如果在定义a的时候没有给赋值null,这个异常是不会出现滴。

 

这...java 究竟是如何加载对象的?

 

就拿此例说明吧,在java new 一个对象的时候,首先声明了自己的所有成员变量,所有成员变量都是null,然后去构造父类,在构造父类的时候我们这里调用了子类的钩子方法,给a赋值为 new object(),父类构造完成之后回到子类构造函数,执行子类构造的内容,此时会检查你在声明成员变量时候有没有给它初始值,有的话就会去执行赋值语句,有异常的代码相当于在声明与赋值之间执行了父类的构造函数。最终a变成了null。

 

经此解释你是否明白为啥了么?呵呵,不明白就自己去debug一下 就海阔天空了:)

 

由此忠告自己以及各位看客:务必不要在构造函数中调用多态。如果你非要这么写那就请不要在调用的方法中使用子类的成员变量

 

 

 

 

多态,如果存在一个基类指针指向派生类对象,并且通过该指针进行析构操作,那么先构造的派生类对象会后析构。 这是因为在多态,析构函数应该是虚函数。当使用基类指针指向派生类对象时,如果析构函数没有被声明为虚函数,那么在执行析构操作时只会调用基类的析构函数,而不会调用派生类的析构函数,这可能导致派生类资源无法正确释放。 为了避免上述问题,需要将基类的析构函数声明为虚函数。这样,当通过基类指针进行析构操作时,会按照派生类的析构顺序依次调用派生类的析构函数,从而确保派生类的资源正确释放。 下面是一个示例代码来说明先构造的派生类对象会后析构的情况: ```cpp #include <iostream> class Base { public: Base() { std::cout << "Base 构造函数" << std::endl; } virtual ~Base() { std::cout << "Base 析构函数" << std::endl; } }; class Derived : public Base { public: Derived() { std::cout << "Derived 构造函数" << std::endl; } ~Derived() { std::cout << "Derived 析构函数" << std::endl; } }; int main() { Base* ptr = new Derived(); delete ptr; return 0; } ``` 在上面的示例,我们定义了一个基类`Base`和一个派生类`Derived`。在`main()`函数,我们使用基类指针`ptr`指向一个派生类对象,并通过该指针进行析构操作。 运行上述代码,输出结果如下: ``` Base 构造函数 Derived 构造函数 Derived 析构函数 Base 析构函数 ``` 可以看到,先构造的派生类对象`Derived`会后析构,即先调用派生类的析构函数,再调用基类的析构函数。这是多态正确释放资源的行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值