类加载机制

类加载机制

1.类的加载,连接和初始化

java源文件–>编译器–>字节码文件–>jvm–>机器码

1.类的加载

当程序使用到某一个类时,如果这个类还没有被加载,则系统会通过,加载,连接和初始化的步骤来对该类进行初始化.类加载指的时将.class文件读入内存,并创建一个java.lang.Class对象.类加载器通常时由JVM来提供的.可以从不同来源的类加载二进制文件.

  • 本地文件系统加载class文件
  • JAR包加载class文件
  • 通过网络加载class文件
  • 把一个Java源文件动态编译,并执行加载

2.类的连接

当类被加载后,系统会生成一个Class对象,接着将会进入连接阶段,连接负责把类的二进制数据合并到jre中,类连接分为三个阶段

  • 验证:验证阶段用于检验被加载的类是否正确的内部结构,并和其他类协调一致。
  • 准备:类准备阶段则负责为类的变量分配内存,并设置默认初始值。
  • 解析:将类的二进制数据中的符号引用替换成直接引用。

3.类的初始化

在类的初始化阶段,虚拟机负责对类进行初始化,主要就是对类变量进行初始化,在java类中对类变量指定初始值有两种方式。

  • 声明变量时指定初始值

  • 使用静态初始化块为类变量指定初始值

    加载顺序实例:

    父类

    @Getter
    @Setter
    public class Parent {
        //父类的静态代码块
        static {
            System.out.println("这是父类静态代码块!");
        }
        //父类的非静态代码块
        {
            System.out.println("这是父类非静态代码块!");
        }
        //父类的属性
        private String name = "张三";
        private int age;
        //父类的构造器
        public Parent(){
            this.name = "李四";
        }
    }
    

    子类

    @Setter
    @Getter
    public class Chidren extends Parent {
        //子类的静态代码块
        static{
            System.out.println("这是子类的静态代码块!");
        }
        //子类的非静态代码块
        {
            System.out.println("这是子类的非静态代码块!");
        }
        //子类的属性
        private double height = 172.5;
        //子类的构造器
        public Chidren(){
            this.height = 175.8;
        }
    }
    

    测试

        /**
         * 本测试测试类初始化加载顺序
         */
        @Test
        public void testClass(){
            Chidren chidren = new Chidren();
            System.out.println(chidren.getHeight());
        }
    

    结果

在这里插入图片描述

字节码文件:

父类的.class文件

// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space 
// Source File Name:   Parent.java

package com.jdbc.review;

import java.io.PrintStream;

public class Parent
{

	private String name;
	private int age;

	public Parent()
	{
		System.out.println("这是父类非静态代码块!");
		name = "张三";
		name = "李四";
	}

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public void setAge(int age)
	{
		this.age = age;
	}

	static 
	{
		System.out.println("这是父类静态代码块!");
	}
}

子类的.class文件

// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://kpdus.tripod.com/jad.html
// Decompiler options: packimports(3) fieldsfirst ansi space 
// Source File Name:   Chidren.java

package com.jdbc.review;

import java.io.PrintStream;

// Referenced classes of package com.jdbc.review:
//			Parent

public class Chidren extends Parent
{

	private double height;

	public Chidren()
	{
		System.out.println("这是子类的非静态代码块!");
		height = 172.5D;
		height = 175.80000000000001D;
	}

	public void setHeight(double height)
	{
		this.height = height;
	}

	public double getHeight()
	{
		return height;
	}

	static 
	{
		System.out.println("这是子类的静态代码块!");
	}
}

由上面的字节码文件不难发现:

​ 1.首先编译器把非静态代码块中的代码放到了构造器的最上面.

​ 2.先加载父类的静态代码块然后是子类的,然后其他的和创建对象的过程没有变.

2.类的加载器

2 类加载器

2.1 类加载器简介

类加载器负责将.calss文件加载到内存中,并为之生成对应的java.lang.Class对象。一旦一个类被载入JVM中,同一个类就不会被再次载入了。一个类的全限定类名和其类加载器作为其唯一标识。当JVM启动时,会形成由三个类加载器组成的初始类加载器。

Bootstrap ClassLoader:
1.根类加载器,它负责加载Java的核心类,他非常特殊,它并不是java.lang.ClassLoader的子类,而是JVM自身实现的。
Extension ClassLoader:
2.扩展类加载器,它负责加载JRE的扩展目录(jre/lib/ext)
System ClassLoader:
3.系统类加载器,它负责加载来自java命令的-classpath选项,java.class.path系统属性,或者CLASSPATH环境变量所指定的JAR包和类路径。

2.2 类加载机制

JVM的类加载机制主要有如下三种

  • 全盘负责:
    所谓全盘负责,就是当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显式使用另外一个类加载器来载入。
  • 父类委托:
    所谓父类委托,则是先让parent(父)类加载器视图加载该Class,只有在父类加器无法加载该类时才尝试从自己的路径中加载该类。
  • 缓存机制:
    缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓冲区中搜索该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将起转成Class对象,存入缓冲区中。这就是为什么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值