Java继承与初始化全过程解析

Java初始化简介

通常来讲,在Java中,每一个类产生的编译代码都存在于它本身的独立文件中,该文件只有在使用程序代码时才会被加载,也就是说,类的代码只有在初次使用时才加载。可是,若是存在static的话,就不同了,当访问static字段或static方法时,也会发生加载。最多见的static方法是构造器方法了,虽然没有显示写明static关键字。因此,更准确地讲,Java的类应该是在其任何static成员被访问时加载的。 java

Java继承的概念

Java面向对象的三大特征是继承、封装、多态。继承的概念顾名思义,相似父子关系,子继承父亲。继承一般被认为是is-a关系,即子类是一个父累,能够这样理解。例如,大黄鸭是一个鸭子。虽然继承是面向对象的一个重大特性,可是对于项目的架构来讲,继承应该慎用,经常使用的模式有组合,组合即一个类中持有另一个类的对象,例如咱们要构造一个汽车时,总要持有发动机、门、窗户、轮子等这些类的具体对象,显然汽车不是一个发动机,也不是一个轮子,它们的关系是has-a的关系,所以须要使用组合模式来设计。在OOP中,使用继承的一个优势是它能够向上转型(upcasting),即子类能够持有父类的方法,或者说子类是一个父类,经过向上转型,进而引出了多态的优势,即当有方法被覆盖时,父类类型的子类对象能够从子类依次向上查找,知道遇到该方法即可调用,这一优势为程序的可扩展性奠基了基础,如要新建一个子类,只用从新覆盖父类中已有的某个方法便可,在调用时便可实现多态的特性。然而,继承的使用场合应该尽可能谨慎,使用前应该问问本身是否须要向上转型,若是后续业务中,必需要进行向上转型,那么就使用继承;不然,大可没必要使用继承。 设计模式

那么,在继承这种设计模式中,程序的加载过程是怎么进行的呢?父类的构造方法会不会加载?若是有static字段或方法,又是如何加载呢? 架构

含有继承的程序加载过程

下面,咱们以一个继承关系的两个类来探讨该问题,类中包含有static字段。 函数

首先,写出基类的代码: spa


package demo0812.demo1;

public class SupClass {

		private int i=9;
		protected int j;
		public SupClass() {
			System.out.println("i="+i+",j="+j);
			j=39;
		}
		private static int x1=printInit("SupClass.x1 initialized");
		protected static int printInit(String str) {
			System.out.println(str);
			return 47;
		}
}
写出子类的代码:



package demo0812.demo1;

public class SubClass extends SupClass {

	private int k=printInit("SubClass.k initialized");
	public SubClass() {
		System.out.println("k="+k);
		System.out.println("j="+j);
	}
	
	private static int x2=printInit("SubClass.x2 initialized");
	public static void main(String[] args) {
		System.out.println("SubClass constructor");
		SubClass subClass = new SubClass();
	}
}
从上面的两个类代码能够看出,基类中含有一个static方法和一个static字段,另外还包含一个显示的构造方法。那么在程序执行过程当中,固然先访问SubClass.main()方法,这是程序的入口,因而加载器开始启动并找出SubClass的编译代码(SubClass.class文件),而后,注意到该类有个关键字extends,说明它有个父类,因而,加载器便去加载父类的代码,即SupClass.class文件。加载器发现父类中含有一个静态字段,因而加载器先加载这个静态字段,同时也加载了静态方法,因而输出
SupClass.x1 initialized
,同时将x1的值赋为47。在加载完父类的静态区域之后,开始加载子类的静态区域,加载器因而看到,在子类中,也有一个静态字段x2,而且对它进行初始化,因而输出
SubClass.x2 initialized
,同时,将x2的值赋为47。这时,父类和子类的静态区都已经加载完成,因而,接着读取main函数,首先输出main中的第一行命令
SubClass constructor
接着,执行第二行命令,即对子类进行实例化,注意对子类实例化以前必定会对父类进行实例化,因而输出
i=9,j=0
接着,对子类进行按序执行,首先输出
SubClass.k initialized

并对k赋值为47,最后输出 设计


k=47
j=39



这就是这段代码的整体的加载流程。
相关文章
相关标签/搜索