继承、初始化及类的加载

来源:互联网 发布:下载gif软件 编辑:程序博客网 时间:2024/04/28 07:12

java的继承和初始化及类的加载是个比较复杂的过程,在看java编程思想的时候书上讲到了这部分。书上的一个例子把这个问题讲的很清楚,代码如下:

class Insect{private int i =9;protected int j;Insect(){System.out.println("i="+i+" j="+j);j = 39;}private static int x = printInit("static Insect.x initialized");static int printInit(String s){System.out.println(s);return 47;}}public class Beetle extends Insect{private int k = printInit("Bettle.k initialized");public Beetle(){System.out.println("k="+k+" j="+j);}private static int x2 = printInit("static beetle initialized");public static void main(String[] args){System.out.println("bettle constructor");Beetle b = new Beetle();}
此时程序的输出结果是:

static Insect.x initialized
static beetle initialized
bettle constructor
i=9 j=0
Bettle.k initialized
k=47 j=39

下面具体分析一下程序的执行过程:

我们知道,java文件的运行首先是类的加载,也就是找到main函数然后进行相关类的加载。对于这个java文件,在运行时程序一开始试图找到Beetle的main方法然后加载Beetle的class文件,在class文件加载的过程中,发现这个Beetle类继承了另外一个类Insect所以程序需要先加载Insect的class文件。之后再加载自身的class文件。此时如果Insect类继承了另外一个类时,以同样的方法类推。这里执行完了类的加载过程。但是让人疑惑的是类在加载的时候,具体执行的操作是什么呢?可以通过修改代码进行测试:

class Insect{private int i =9;protected int j;Insect(){System.out.println("i="+i+" j="+j);j = 39;}private static int x = printInit("static Insect.x initialized");static int printInit(String s){System.out.println(s);return 47;}}public class Beetle extends Insect{private int k = printInit("Bettle.k initialized");public Beetle(){System.out.println("k="+k+" j="+j);}private static int x2 = printInit("static beetle initialized");//public static void main(String[] args)//{//System.out.println("bettle constructor");//Beetle b = new Beetle();//}//}
上面的代码注释掉了main方法,运行一下看看是什么结果:

static Insect.x initialized
static beetle initialized
java.lang.NoSuchMethodError: main
Exception in thread "main" 

程序提示说找不到main方法,那是肯定的因为main方法被注释掉了。然而需要注意的是,没有main方法也就是说程序并未真正执行但程序输出了static Insect.x initialized,static beetle initialized这两句。似乎不可理解。我都没有main方法,怎么会有输出呢?仔细分析一下,首先我们看看输出的这两句有什么特点?不错,他们都是用static修饰的。然后我们再看看他们的输出顺序,Insect.x先输出而beetle后输出。这是为什么呢?这到底是为什么呢?好像有那么点明白了,对,不错,就是上面说到的类加载顺序嘛!理理头绪,首先加载Insect类然后加载Beetle类,而加载时干嘛呢?输出了两个句子,为什么输出者两个句子?因为他们是static修饰的。这下算是彻底搞明白了,程序加载时如果遇到static修饰的部分则直接执行,也就是是static修饰的部分是在编译期执行的!ok,终于明白鸟。

接着我们来分析一下

bettle constructor
i=9 j=0
Bettle.k initialized
k=47 j=39

这些语句是如何输出的。首先是bettle constructor,这点容易理解,因为它是我在main方法中直接打印的。而i=9 j=0是如何输出的呢?看看我们的源程序,找到这个语句的输出位置,发现是在Insect的构造方法中,也就是说在使用Beetle b = new Beetle();声明一个Beetle对象时,首先调用的是父类也就是Insect类的构造方法,此时输出了i和j。而i在声明是直接初始化为9所以输出的是i=9;而j在声明是未初始化,所以使用系统自动初始化:j=0。并且j的值被赋予j=39。在调用了Insect的构造方法后,调用Beetle的构造方法。而Bettle的构造方法中需要输出k的值,所以调用了printInit方法,输出了Bettle.k initialized,k被赋予47于是输出了k=47而此时的j已经在前面被赋予所以输出j=39。至此我们分析完了整个程序的执行流程。

总结一下:程序执行时,首先加载自身的class文件如果这个类继承了另外一个类则先加载父类的class文件之后加载自己的class文件。而在加载class文件时,如果程序中有static修饰的部分则直接执行。(static修饰的部分是编译期部分)在所有类的class文件都加载完后,创建对象时则先使用父类的构造器创建父类的对象,之后使用自己的构造器创建自己的对象。而在创建对象时,各个变量按照出现的顺序依次初始化。




原创粉丝点击