之前说过Java中类的加载顺序,这次看完继承部分,就结合继承再来说说类的加载顺序。

继承的加载顺序

由于static块会在首次加载类的时候执行,因此下面的例子就是用static块来测试类的加载顺序。

package xing.test.thinking.chap7;
class A{
static{
System.out.println("A static");
}
}
class B extends A{
static{
System.out.println("B static");
}
}
class C extends B{
private static D d = new D();
static{
System.out.println("C static");
}
}
class D{
static{
System.out.println("D static");
}
}
public class ExtendTest {
public static void main(String[] args) {
C c = new C();
}
}

在上面的例子中,类C继承B,B继承A,而C有依赖于D。因此当创建C的时候,会自动加载C继承的B和依赖的D,然后B又会加载继承的A。只有A加载完,才能顺利的加载B;BD加载完,才能加载C。这就是类的加载顺序了。

A static
B static
D static
C static

所有的变量初始化完,才会执行构造方法

在类的加载过程中,只有内部的变量创建完,才会去执行这个类的构造方法。

package xing.test.thinking.chap7;
class A2{
B2 b2 = new B2();
static{
System.out.println("A static");
}
public A2() {
System.out.println("A2()");
}
}
class B2{
C2 c2 = new C2();
D2 d2 = new D2();
static{
System.out.println("B static");
}
public B2() {
System.out.println("B2()");
}
}
class C2{
static{
System.out.println("C static");
}
public C2() {
System.out.println("C2()");
}
}
class D2{
static{
System.out.println("D static");
}
public D2() {
System.out.println("D2()");
}
}
public class VarTest {
public static void main(String[] args) {
A2 a2 = new A2();
}
}

在上面的例子中,A2里面有B2变量,B2则有C2D2变量。因此类的加载还是先读取到哪个,就执行相应的静态块。

当依赖的对象都定义完,才会执行构造方法:

A static
B static
C static
C2()
D static
D2()
B2()
A2()

静态成员与普通成员类的加载区别

在类的加载过程中,静态成员类的对象,会优先加载;而普通成员类的对象则是使用的时候才回去加载。

package xing.test.thinking.chap7;
class A3{
B3 b3 = new B3();
static C3 c4 = new C3();
static{
System.out.println("A3");
}
}
class B3{
static{
System.out.println("B3");
}
}
class C3{
static{
System.out.println("C3");
}
}
public class StaticTest {
public static void main(String[] args) {
A3 a3 = new A3();
}
}

输出:

C3
A3
B3

总结

第一点,所有的类都会优先加载基类

第二点,静态成员的初始化优先

第三点,成员初始化后,才会执行构造方法

第四点,静态成员的初始化与静态块的执行,发生在类加载的时候。

第四点,类对象的创建以及静态块的访问,都会触发类的加载。

补充类构造方法的顺序

看代码:

package xing.test.thinking.chap8;
class A{
public A() {
System.out.println("A");
}
}
class B extends A{
public B() {
System.out.println("B");
}
}
class C extends B {
private D d1 = new D("d1");
private D d2 = new D("d2");
public C() {
System.out.println("C");
}
}
class D {
public D(String str) {
System.out.println("D "+str);
}
}
public class ExtendTest {
public static void main(String[] args) {
C c = new C();
}
}

执行结果:

A
B
D d1
D d2
C

因此可以得出结论:

  • 首先会调用基类的构造方法
  • 其次,调用成员的构造方法
  • 最后,调用自己的构造方法

Java程序员的日常 —— Java类加载中的顺序的更多相关文章

  1. Java程序员的日常—— 垃圾回收中引用类型的作用

    在Java里面,是不需要太过于关乎垃圾回收,但是这并不意味着开发者可以不了解垃圾回收的机制,况且在java中内存泄露也是家常便饭的事情.因此了解垃圾回收的相关知识就显得很重要了. 引用,在垃圾回收中是 ...

  2. Java程序员的日常——经验贴(纯干货)

    工作当中遇到的事情比较杂,因此涉及的知识点也很多.这里暂且记录一下,今天遇到的知识点,纯干货~ 关于文件的解压和压缩 如果你的系统不支持tar -z命令 如果是古老的Unix系统,可能并不认识tar ...

  3. Java程序员的日常—— Properties文件的读写

    在日常的Java程序开发中,Properties文件的读写是很常用的.经常有开发系统通过properties文件来当做配置文件,方便用户对系统参数进行调整. 那么本片就来简单的介绍下,如何使用Prop ...

  4. Java程序员的日常—— 《编程思想》关于类的使用常识

    Java虽然利用JVM,让程序员可以放心大胆的使用,可是仍然会出现内存泄露等问题.世上没有绝对的银弹,因此也不能完全把所有的任务都交给JVM,了解Java中的初始化与垃圾回收还是必不可少的知识. 关于 ...

  5. Java程序员的必备知识-类加载机制详解

    类加载器的概念 类加载器是一个用来加载类文件的类. Java源代码通过javac编译器编译成类文件.然后JVM来执行类文件中的字节码来执行程序.类加载器负责加载文件系统.网络或其他来源的类文件. JV ...

  6. Java程序员的日常 —— 多进程开发

    最近再弄进程管理相关的工作,因此必要的就涉及到各种系统下关于进程的管理. 这里简单的介绍下: 如何在Java中执行命令 在windows下肯定是dos命令了,而在linux则为shell命令.执行的方 ...

  7. Java程序员的日常—— Arrays工具类的使用

    这个类在日常的开发中,还是非常常用的.今天就总结一下Arrays工具类的常用方法.最常用的就是asList,sort,toStream,equals,copyOf了.另外可以深入学习下Arrays的排 ...

  8. Java程序员入门:Java程序员面试失败的5大原因

    1 说得太少 尤其是那些开放式的问题,如"请介绍下你自己"或"请讲一下你曾经解决过的复杂问题".面试官会通过你对这些技术和非技术问题的回答来评估你的激情.他们也 ...

  9. Java程序员注意——审查Java代码的六种常见错误

    代码审查是消灭Bug最重要的方法之一,这些审查在大多数时候都特别奏效.由于代码审查本身所针对的对象,就是俯瞰整个代码在测试过程中的问题和Bug.并且,代码审查对消除一些特别细节的错误大有裨益,尤其是那 ...

随机推荐

  1. Pure.css网格系统学习心得——图片的响应式以及应用填充和边框网格单位的学习

    今天学习了pure.css可定制的网格系统,pure默认的网格系统是移动先行,如果我们想在小屏幕上有网格只要用pure-u-*就可以了,下面来说一下它的主要用法! <div class=&quo ...

  2. centos 7安装配置bind

    环境: 三台虚拟机,全部安装Centos 7, tony4.hadoop.com 192.168.31.223 tony5.hadoop.com 192.168.31.224 tony6.hadoop ...

  3. 分离式模型separation model

    1.关键字export 在头文件中定义模板,并且在模板的定义以及声明前添加关键字export. exported 模板可以直接使用,不需要看到该模板定义.模板的使用和定义可以分割于两个不同的编译单元. ...

  4. Cobbler学习之二--Cobbler的Web管理和维护

    Cobbler的Web管理模块和命令行模块是可以分开工作的,没有依赖关系. 1 WebUI的功能 查看所有的对象和配置文件 添加或者删除system,distro, profile 执行“cobble ...

  5. vijos1910解方程

      描述 已知多项式方程: a0+a1x+a2x2+...+anxn=0a0+a1x+a2x2+...+anxn=0 求这个方程在[1, m]内的整数解(n 和 m 均为正整数). 格式 输入格式 输 ...

  6. Irrlicht 鬼火

    1.下载引擎 2.引入头文件 在VS2010下新建项目,项目->属性->配置属性->VC++目录 在包含目录中:添加 引擎安装目录\include\ 在库目录中:添加 引擎安装目录\ ...

  7. Linux磁盘管理

    本系列的博客来自于:http://www.92csz.com/study/linux/ 在此,感谢原作者提供的入门知识 这个系列的博客的目的在于将比较常用的liunx命令从作者的文章中摘录下来,供自己 ...

  8. haproxy的使用

    假如 www.example.com想要使用haproxy作为代理,则要在自己的 dns服务器设置AAAA记录对应于haproxy机器的IP. 这样访问www.example.com其实就访问了hap ...

  9. WinAPI: GetKeyNameText - 根据键盘消息获取按键名称

    ;  Canvas.Font.Style := [fsBold];  Canvas.Font.Color := clRed;  Canvas.Brush.Color := clWhite;..] of ...

  10. 字符串混淆技术在.NET程序保护中的应用及如何解密被混淆的字符串

    Visual Studio提供的Dotfuscator保护程序,可以对用户代码中包含的字符串进行加密.比如下面的例子,为了找到这个程序的注册算法,用.NET Reflector加载程序集后,发现代码中 ...