栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java类的加载顺序和JVM双亲委派模型

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java类的加载顺序和JVM双亲委派模型

参考
深入理解Java对象的创建过程:类的初始化与实例化
深入JVM 双亲委派模型
【jvm】通过JDBC为例谈谈双亲委派模型的破坏
为什么JVM的类加载要采用双亲委派的加载机制?

Java对象创建方式

父类代码和子类代码如下:

//父类
public class SuperClass {

    private String name;

    private static int age;

    {
        name = "hh";
        System.out.println("父类。。初始化实例块。。");
    }

    static {
        age = 18;
        System.out.println("父类。。初始化静态代码块。。");
    }

    public SuperClass(String name) {
        System.out.println("父类。。有参构造函数。。");
        this.name = name;
    }

    public SuperClass() {
        System.out.println("父类。。无参构造函数。。");
    }

    @Override
    public String toString() {
        return "SuperClass{" +
                "name='" + name + ''' +
                "age" + age + ''' +
                '}';
    }
}

//子类
public class SubClass extends SuperClass {
    private String company;

    private static String phone;

    {
        company = "wangwang";
        System.out.println("子类。。初始化实例块。。");
    }

    static {
        phone = "1888888888";
        System.out.println("子类。。初始化静态代码块。。");
    }

    public SubClass(String name, String company) {
        super(name);
        this.company = company;
        System.out.println("子类。。有参构造函数1。。");
    }

    public SubClass(String company) {
        this.company = company;
        System.out.println("子类。。有参构造函数2。。");
    }

    public SubClass() {
        System.out.println("子类。。无参构造函数。。");
    }

    @Override
    public String toString() {
        return super.toString() + "SubClass{" +
                "company='" + company + ''' +
                "phone='" + phone + ''' +
                '}';
    }
}

  1. 使用new关键字
SubClass subClass = new SubClass("Willow","niu");
  1. 使用Class类的newInstance方法(反射机制)

newInstance方法调用无参构造器创建对象

SubClass subClass = (SubClass) Class.forName("com.bean.SubClass").newInstance();
SubClass subClass = SubClass.class.newInstance();
  1. 使用Constructor类的newInstance方法(反射机制)

该方法和Class类中的newInstance方法很像,但Constructor类的newInstance可以调用有参数的和私有的构造函数

Constructor constructor = SubClass.class
                .getConstructor(String.class);
SubClass subClass = constructor.newInstance("Willow");
  1. 使用Clone

调用clone()方法时:1.对象必须继承Cloneable 2、必须重载clone方法。

//继承+override clone(),其他同上
public class SubClass extends SuperClass implements Cloneable {
   
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

//创建时调用
SubClass subClass = new SubClass("Willow","niu");
SubClass subClass2 = (SubClass) subClass.clone();
  1. 使用(反)序列化机制

当反序列化一个对象时,JVM会创建一个单独对象并且不会调用任何构造函数。为了反序列化一个对象,类必须实现Serializable接口。

父类实现Serializable接口

public class SuperClass implements Serializable 

反序列化对象

    public static void main(String[] args) throws Exception {
        SubClass subClass = new SubClass("Willow","Willow's company");
        ObjectOutputStream output = new ObjectOutputStream(
                new FileOutputStream("SubClass.txt"));
        output.writeObject(subClass);
        output.close();

        System.out.println(subClass);
        System.out.println("***********************");

        ObjectInputStream input = new ObjectInputStream(new FileInputStream(
                "SubClass.txt"));
        SubClass outSubClass = (SubClass) input.readObject();
        System.out.println(outSubClass);
        input.close();
    }

输出结果

类的加载顺序

虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块叫“类加载器”

类加载器就是寻找类或接口字节码文件进行解析并构造JVM内部对象表示的组件,在java中类装载器把一个类装入JVM,经过以下步骤:

  1. 加载:查找和导入Class文件
  2. 链接:其中解析步骤是可以选择的 (a)检查:检查载入的class文件数据的正确性 (b)准备:给类的静态变量分配存储空间
    (c)解析:将符号引用转成直接引用
  3. 初始化:对静态变量,静态代码块执行初始化工作
public class Demo1Application {
    public static void main(String[] args) throws Exception {
        SubClass subClass = new SubClass("Willow","niu");
        System.out.println(subClass);
    }
}

结果如下:

在类中,加载顺序为:
1.首先加载父类的静态字段或者静态语句块。
2.子类的静态字段或静态语句块。
3.父类普通变量以及语句块。
4.父类构造方法被加载。
5.子类变量或者语句块被加载。
6.子类构造方法被加载。
静态方法,调用的时候才会加载,不调用的时候不会加载。
静态语句块和静态变量被初始化的顺序与代码先后顺序有关。

JVM双亲委派模型

JVM双亲委派模型:如果一个类加载器收到类加载请求,它不会立刻加载这个类,而是将请求委派给父类加载器去加载该类,最终加载请求会打到引导类加载器,只有当父类加载器无法完成加载请求(也就是搜索范围内无该类),子加载器才会自己尝试去加载这个类。

为什么JVM的类加载要采用双亲委派模型加载类?

基于双亲委派模型设计,那么Java中基础的类,Object类似Object类重复多次的问题就不会存在了,因为经过层层传递,加载请求最终都会被Bootstrap ClassLoader所响应。加载的Object类也会只有一个,否则如果用户自己编写了一个java.lang.Object类,并把它放到了ClassPath中,会出现很多个Object类,这样Java类型体系中最最基础的行为都无法保证,应用程序也将一片混乱。

双亲委派模型的好处:
1.安全性,避免用户自己编写的类动态替换JAVA的一些核心类。
2.避免类的重复加载,因为JVM中区分不同类,不仅仅是根据类名,相同的class文件被不同的ClassLoader加载就是不同的两个类。

在JVM中表示两个class对象是否为同一个类对象存在两个必要条件:
1.类的全限定名必须一致,包括包名。
2.加载这个类的ClassLoader(指ClassLoader实例对象)必须相同。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/323302.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号