摘要:很多时候提到类加载,大家总是没法马上回忆起顺序,这篇文章会用一个例子为你把类加载的诸多问题一次性澄清。

本文分享自华为云社区《用1个例子加5个问题,一次性搞清java中的类加载问题【奔跑吧!JAVA】》,原文作者:breakDraw 。

很多时候提到类加载,大家总是没法马上回忆起顺序,这篇文章会用一个例子为你把类加载的诸多问题一次性澄清。

Java类的加载顺序

引用1个网上的经典例子,并做稍许改动,以便大家更好地理解。

原例子引用自:https://blog.csdn.net/zfx2013/article/details/89453482

public class Animal {
private int i = test();
private static int j = method();
static {
System.out.println("a");
}
Animal(){
System.out.println("b");
}
{
System.out.println("c");
}
public int test(){
System.out.println("d");
return 1;
}
public static int method(){
System.out.println("e");
return 1;
}
}
public class Dog extends Animal{
{
System.out.println("h");
}
private int i = test();
static {
System.out.println("f");
}
private static int j = method(); Dog(){
System.out.println("g");
}
public int test(){
System.out.println("i");
return 1;
}
public static int method(){
System.out.println("j");
return 1;
}
public static void main(String[] args) {
Dog dog = new Dog();
System.out.println();
Dog dog1 = new Dog();
}
}

执行这段main程序,会输出什么?
答案是
eafjicbhig
icbhig

为了方便大家一个个细节去理解, 我换一种方式去提问。
Q: 什么时候会进行静态变量的赋值和静态代码块的执行?
A:

  • 第一次创建某个类或者某个类的子类的实例
  • 访问类的静态变量、调用类的静态方法
  • 使用反射方法forName
  • 调用主类的main方法(本例子的第一次静态初始化其实属于这个情况,调用了Dog的main方法)
    注: 类初始化只会进行一次, 上面任何一种情况触发后,之后都不会再引起类初始化操作。

Q:初始化某个子类时,也会对父类做静态初始化吗?顺序呢?
A:如果父类之前没有被静态初始化过,那就会进行, 且顺序是先父类再子类。 后面的非静态成员初始化也是如此。
所以会先输出eafj。

Q: 为什么父类的method不会被子类的method重写?
A: 静态方法是类方法,不会被子类重写。毕竟类方法调用时,是必定带上类名的。

Q: 为什么第一个输出的是e而不是a?
A: 因为类变量的显示赋值代码和静态代码块代码按照从上到下的顺序执行。
Animal的静态初始化过程中,method的调用在static代码块之前,所以先输出e再输出a。
而Dog的静态初始化过程中,method的调用在static代码块之后,因此先输出f,再输出j

Q: 没有在子类的构造器中调用super()时,也会进行父类对象的实例化吗?
A: 会的。会自动调用父类的默认构造器。 super()主要是用于需要调用父类的特殊构造器的情况。
因此会先进行Animal的对象实例化,再进行Dog的对象实例化

Q: 构造方法、成员显示赋值、非静态代码块(即输出c和h的那2句)的顺序是什么?
A:

  1. 成员显示赋值、非静态代码块(按定义顺序)
  2. 构造方法
    因此Animal的实例化过程输出icb(如果对输出i有疑问,见下面一题)
    接着进行Dog的实例化,输出hig

Q: 为什么Animal实例化时, i=test()中输出的是i而不是d?
A:因为你真正创建的是Dog子类,Dog子类中的test()方法由于签名和父类test方法一致,因此test方法被重写了。
此时即使在父类中调用,也还是用使用子类Dog的方法。除非你new的是Animal。

Q: 同上题, 如果test方法都是private或者final属性, 那么上题的情况会有变化吗??
A:
因为private和final方法是不能被子类重写的。
所以Animal实例化时,i=test输出d。

总结一下顺序:

  1. 父类静态变量显式赋值、父类静态代码块(按定义顺序)
  2. 子类静态变量显式赋值、子类静态代码块(按定义顺序)
  3. 父类非静态变量显式赋值(父类实例成员变量)、父类非静态代码块(按定义顺序)
  4. 父类构造函数
  5. 子类非静态变量(子类实例成员变量)、子类非静态代码块(按定义顺序)
  6. 子类构造函数。

类加载过程

Q:类加载的3个必经阶段是:
A:

  1. 加载(类加载器读取二进制字节流,生成java类对象)
  2. 链接(验证,分配静态域初始零值)
  3. 初始化(前面的题目讲的其实就是初始化时的顺序)
    更详细的如下:

被动引用中和类静态初始化的关系

Q:new某个类的数组时,会引发类初始化吗?
像下面输出什么

public class Test {
static class A{
public static int a = 1;
static{
System.out.println("initA");
}
} public static void main(String[] args) {
A[] as = new A[5];
}
}

A:
new数组时,不会引发类初始化。
什么都不输出。

Q:引用类的final静态字段,会引发类初始化吗?
像下面输出什么?

public class Test {
static class A{
public static final int a = 1;
static{
System.out.println("initA");
}
} public static void main(String[] args) {
System.out.println("A.a=" + A.a);
}
}

A: 不会引发。
不会输出initA。 去掉final就会引发了。
(注意这里必须是基本类型常量, 如果是引用类型产量,则会引发类初始化)

Q:子类引用了父类的静态成员,此时子类会做类初始化嘛?
如下会输出什么

public class Test {
static class A{
public static int a = 1;
static{
System.out.println("initA");
}
} static class B extends A{
static {
System.out.println("initB");
}
} public static void main(String[] args) {
System.out.println("B.a=" + B.a);
}
}

A:
子类不会初始化。
打印initA,却不会打印initB。

类加载器

双亲委派

类加载时的双亲委派模型,不知道能怎么出题。。。反正就记得优先去父类加载器中看类是否能加载。

就贴个图吧:

注意,上面的图有问题。
Bootsrap不是ClassLoader的子类,他是C++编写的。
而ExtClassLoader和AppClassLoader都是继承自ClassLoader的

Q:java中, 是否类和接口的包名和名字相同, 那么就一定是同一个类或者接口?
A:错误。
1个jvm中, 类和接口的唯一性由 二进制名称以及它的定义类加载器 共同决定。
因此2个不同的加载器加载出来相同的类或接口时, 实际上是不同的。

点击关注,第一时间了解华为云新鲜技术~

一次性搞清Java中的类加载问题的更多相关文章

  1. Java中的类加载器

    转载:http://blog.csdn.net/zhangjg_blog/article/details/16102131 从java的动态性到类加载机制   我们知道,Java是一种动态语言.那么怎 ...

  2. Java中的类加载器以及Tomcat的类加载机制

    在加载阶段,虚拟机需要完成以下三件事情: 1.通过一个类的全限定名来获取其定义的二进制字节流. 2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构. 3.在Java堆中生成一个代表这个类 ...

  3. Java中的类加载器--Class loader

    学习一下Java中的类加载器,这个是比较底层的东西,好好学习.理解一下.  一.类加载器的介绍 1.类加载器:就是加载类的工具,在java程序中用到一个类,java虚拟机首先要把这个类的字节码加载到内 ...

  4. [读书笔记]java中的类加载器

    以下内容大多来自周志明的<深入理解Java虚拟机>. 类加载器是java的一项创新,也是java流行的重要原因之一,它最初是为了满足java applet的需求而开发出来. 什么是appl ...

  5. java中的类加载器ClassLoader和类初始化

    每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一条类加载器链,一般的,我们只会用到一 ...

  6. 关于java中的类加载器

    什么是类加载器? 类加载器是专门负责加载类的命令或者说工具 ClassLoader java中的3个类加载器 JDK中自带了3个类加载器 启动类加载器 扩展类加载器 应用类加载器 假设有这样一段代码 ...

  7. Java中的类加载器----ClassLoader

    1.简单的讲类加载器就是加载类. 在一个类要被执行时,首先会被从硬盘中加载到内存中,这个任务就是由类加载器来完成,如果加载不成功时,类是无法被执行的.类加载器执行的都是字节码二进制文件.   帮助文档 ...

  8. java中获取类加载路径和项目根路径的5种方法

    import java.io.File; import java.io.IOException; import java.net.URL; public class MyUrlDemo { publi ...

  9. java中获取类加载路径和项目根路径的5种方式分析

    package my; import Java.io.File; import java.io.IOException; import java.net.URL; public class MyUrl ...

随机推荐

  1. MySQL修改账号密码方法大全

    前言: 在日常使用数据库的过程中,难免会遇到需要修改账号密码的情景,比如密码太简单需要修改.密码过期需要修改.忘记密码需要修改等.本篇文章将会介绍需要修改密码的场景及修改密码的几种方式. 1.忘记 r ...

  2. 2020中国大学生程序设计竞赛(CCPC) - 网络选拔赛总结

    1003 Express Mail Taking 题意:有n个柜子(编号1-n),m封信,k号位置有钥匙,现在需要取信封,并且每取一次信封都要从k号位置进行领取一次钥匙,再去有信封的位置领取信封,问最 ...

  3. 我写了一个简单的JSON序列化和反序列化的工具

    背景 互联网上有许多可用的Json序列化和反序列化的工具,例如fastjson,jackson,Gson等等,那么,我为什么还要自己写一个? 项目不方便依赖其他第三方库.比如有时候我们编写SDK,考虑 ...

  4. [MySQL数据库之记录的详细操作:增、改、删、单表查询、多表查询]

    [MySQL数据库之记录的详细操作:增.改.删.单表查询.多表查询] 记录详细操作 增.删.改 增: insert t1(字段1,字段2,字段3) values (值1,值2,值3), (值1,值2, ...

  5. DataGear 变更部署数据库为SQL Server填坑指南(含转写后的SQL server代码及SQL server配置文件)

    1. 引言 2. 配置数据库链接 3. 引入数据库驱动 4. 手动初始化数据库 5. 改写SQL 6. 其他 7. 参考 1. 引言 DataGear默认使用Derby数据库作为系统的元数据库,至于待 ...

  6. powercli创建虚拟机步骤及批量创建脚本

    https://pubs.vmware.com/vsphere-51/index.jsp?topic=%2Fcom.vmware.powercli.cmdletref.doc%2FSet-OSCust ...

  7. [刷题] 51 N-Queens

    要求 将n个皇后摆放在n*n的棋盘中,使横.竖和两个对角线方向均不会同时出现两个皇后 思路 尝试在一行中摆放,如果摆不下,回到上一行重新摆放,直到所有行都摆下 快速判断不合法情况 竖向:col[i]表 ...

  8. ocalhost kernel: [244840.301449] nf_conntrack: nf_conntrack: table full, dropping packet

    nf_conntrack: table full, dropping packet. 终结篇   "连接跟踪表已满,开始丢包"!相信不少用iptables的同学都会见过这个错误信息 ...

  9. 面试阿里P6难在哪?(面试难点)

    对于很多没有学历优势的人来说,面试大厂是非常困难的,这对我而言,也是一样,出身于二本,原本以为就三点一线的生活度过一生,直到生活上的变故,才让我有了新的想法和目标,因此我这个二本渣渣也奋斗了起来,竟拿 ...

  10. TEB 系统综合误差

    TEB  系统综合误差  和森世籍  聊天得知 该TEB  包括  传感器误差  温度  系统误差等等