首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java中类的加载机制---父类和子类的多态调用

Java中类的加载机制---父类和子类的多态调用

作者头像
wust小吴
发布2019-07-08 16:42:46
2.7K0
发布2019-07-08 16:42:46
举报
文章被收录于专栏:风吹杨柳风吹杨柳

一个最经典的程序是这样的:

public class ExtendsInstanceTest {

	private String baseName = "base";

	public ExtendsInstanceTest() {
		callName();
	}

	public void callName() {
		System.out.println(baseName);
	}

	static class Sub extends ExtendsInstanceTest {
		private String baseName = "sub";

		public void callName() {
			System.out.println(baseName);
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ExtendsInstanceTest b = new Sub();
	}

}

他的输出结果是  null

1)

上面程序最大的难点,也是最重要的地方就是:在父类的构造函数中调用了虚函数,并且这个函数被子类重载了

2)

继承的时候,子类与父类有着同名的属性和同名的方法,关于同名的属性的初始化过程也是必须要了解的。同名的属性会不会被覆盖掉,同名的方法就是多态,同名的方法之间的调用是怎么样的。

3)

类构造的时候,Java机制是到底先给属性分配空间并赋值,还是先处理 构造函数,换句话说,当我们使用new操作符生成一个对象的实例的时候,类的加载机制是怎么样的,

如果这三个问题都搞定了,都理解了,上面的程序就很容易理解为什么输出是null了

Java机制里面有这样的一个原则就是:如果父类存在,子类可以不存在;如果子类存在,父类必须存在;

怎么理解上面的这句话呢,可以用实际的例子来说明,一个人结婚了但是没有小孩,对应着前半句的意思;如果他生了小孩,那么这个小孩子是一定有父亲的

到Java代码中这样看,如果我们实例化一个子类,必须先构造这个子类的父类,否则是错误的。也就是说,父类的存储空间的分配是在子类前面完成的;还可以这样说,当执行到子类的构造函数的时候,首先第一个代码是执行super(),哪怕你没有显示的写出来,他也是会去执行父类的实例化,这就是子类如果想完成初始化,必须先把父类搞定。

Java类加载的机制是第二个需要理解的地方就是:

1)类加载机制首先是  分配内存空间(堆空间,物理存储地址,每个属性都需要分配物理空间,【方法是不需要的】,且这个时候物理空间指向的是空null);

2)当空间分配好之后,进行属性初始化,把值放在栈空间中,前面的第一步过程中物理空间存储地址 指向  这个栈空间,这样就完成了属性值的初始化;

3)当属性值完成了初始化的时候,就开始调用构造函数了,执行构造函数里面的代码块

这个过程说白了,就是一个类加载的时候,执行过程,必须等所有的存储空间都分配好,才能够赋值,而不是一个属性分配好变量之后立刻就赋值,这个理解是错误的。

Java 中子类加载的机制是第三个需要理解的地方:

1)相关的类的加载机制还是跟  上面第二点相似,只是在子类初始化的时候必须先去初始化父类

2)只有 等Java机制给子类和所有的父类都分配了内存空间之后,先搞定堆内存,指向null;才会去  进行属性值的初始化,也就是在栈空间里面是属性的内容,前面分配的内存空间地址这个时候就指向  栈内存的  值;

3)最后就是注意  同名属性不会被子类给覆盖掉的,只是把父类的隐藏掉;同名方法是多态,只会去调用子类的重载方法,

这个规则说白了,就是当有父类和子类的时候,必须都所有的存储空间都分配好了,才能执行  属性的初始化,继而是构造函数;同时要明白一点,子类的构造函数是在父类的构造完成之后才会去执行,必须遵行只有了父亲才有孩子这个规则

上面的三个东西搞明白了,上面的程序就更好理解了

在main函数里面:new 了一个子类 Sub,Java机制是这样做的:

1)第一步首先在堆内存里面,为Sub分配内存空间,主要是属性 baseName ,地址变量指向null,

2)接下来执行Sub的构造函数,首先是执行super()函数,把父类搞出来,

3)进入父类的实例化,首先需要去在堆内存里面给父类分配内存空间,为父类的baseName分配地址,地址变量指向null;

4)由于父类不需要再也没有超类了,那么这个时候父类和子类的内存分配都做完了,接下来就是需要为  属性进行初始化的工作

5)首先是给父类的baseName执行初始化操作,在栈内存里面写上内容base,上面的为父类分配的地址变量  指向  这个栈内存

6)接下来是做父类的构造函数,完成父类的实例化,构造函数里面的代码是执行了一个虚函数,这个时候首先要看子类有没有重载这个函数,多态的调用

7)子类有重载,所以调用子类的方法,但是子类的baseName还没有初始化,所以就没有直接打出null了

8)父类创建完毕,接下来就是去执行子类的创建工作了,

9)首先为子类的属性进行初始化,在栈内存里面放上内容 sub;

10)接下来是去执行子类的构造函数,没有,是默认的无参

整个过程就完整了,

上面的例子最主要的就还是:关于在构造函数里面执行多态方法的时候,应该注意的地方

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015年12月26日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档