首页 > 编程语言 >简单梳理java中的类加载

简单梳理java中的类加载

时间:2023-09-09 09:22:28浏览次数:43  
标签:java name parent 梳理 findClass Class 加载

一、类加载器简介

java中自带的类加载器可以分为根类加载器(BootStrap classloader),扩展类加载器,应用类加载器,这三个都不是用java语言实现的。

其中根类加载器和扩展类加载器用来加载java自带的一些类,而应用类加载器用来加载我们自己写的java类编译后的class文件,也就是classpath中的class文件。

类加载器在java中的继承体系是这样的,顶层父类是ClassLoader

注意扩展类加载器和APPClassloader实际不是用java语言实现的。自定义类加载器时可以继承UrlClassLoader

类加载器加载资源的时候采用的是双亲委派机制:1.每个类加载器对它加载过的类都会缓存,

2.向上委托查找,向下委托加载。只有它的父亲中找不到某个类时才会自己去加载某个类

所以加载某个类时是按这样的顺序去加载

要注意类加载之间的父子关系不是通过继承实现的,是通过持有parent属性实现的

BootStrap classloader ==> ExtClassLoader ==> AppClassLoader,

AppClassLoader中持有的parent属性是ExtClassLoader ,

ExtClassLoader中持有的parent属性是BootStrap classloader,也就是根类加载器

BootStrap classloader中持有的parent属性是null

二. ClassLoader中方法介绍

ClassLoader是类加载器的顶层抽象类,其中定义了类加载的一些通用方法

AppClassLoader,ExtClassLoader,还有自定义类加载器都会继承它

2.1 loadClass(String name, boolean resolve)

这方法是双亲委派机制的实现,

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            //某个类加载器从自己的缓存中看是否加载过某个类
            Class<?> c = findLoadedClass(name);
            //没加载过,向上委托父类查找
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                	//这一块是双亲委派,让父加载器查找的实现
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                       //让根类加载器去查找类
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
				
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    //走到这里表示在父加载器中没找到,需要让子加载器加载
                    long t1 = System.nanoTime();
                    //调用自身的findClass方法去加载类
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

2.2 findClass(String name)

这个方法在ClassLoader中直接抛出异常,需要让子类去重写它实现自己的加载逻辑

protected Class<?> findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
}

一个具体类加载器的findClass方法一般会先加载类的文件得到字节数组,然后调用defineClass方法转成Class对象返回,类似下面这样,这个defineClass是ClassLoader中的方法

public Class findClass(String name) {
    //读取文件得到字节数组
    byte[] b = loadClassData(name);
    //把字节数组转成Class文件,该方法定义在ClassLoader中
    return defineClass(name, b, 0, b.length);
}

2.3 defineClass

defineClass方法用来把自己数组转成Class对象,提供给findClass方法调用

三、自定义类加载

所以我们自定义类加载时,一般会继承ClassLoader,然后重写其findClass方法,这样不会破坏双亲委派机制,如果需要打破双亲委派机制则需要重写loadClass方法。

标签:java,name,parent,梳理,findClass,Class,加载
From: https://www.cnblogs.com/chengxuxiaoyuan/p/17688910.html

相关文章

  • Java基础知识
    一、基础知识注释的作用解释说明程序,提高程序的阅读性帮助我们调试程序Java语言最基本的单位的类,所以我们首先要定义一个类Java程序要想能够独立运行,必须要有主方法如果想要Java程序有输出,必须要有输出语句定义类的格式:classclassname{......
  • java8学习
    java8安装与环境变量配置chocochoco官网安装命令:chocoinstalljdk8自动配置环境变量IDEA官网安装java语法注:由于默认具有cpp基础,所以和cpp极为相似的点我不会提及。enum枚举publicenumPlayerType{TENNIS("网球"),FOOTBALL("足球"),//常量FOOTBALL......
  • 使用 idea debug 远程 java 进程
    线上环境使用的jdk版本为1.8,对应的java启动命令java-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=50050-jarxxxx.jar注意服务器需要开放对应的50050tcp端口idea配置:Run->EditConfiguration->+->RemoteJVMDebug->填写ip端口->启......
  • Java学习_004 数据输入:案例2
    需求:三个和尚的身高需要手动输入,请用程序实现这三个和尚的最高身高。importjava.util.Scanner;publicclassMain{publicstaticvoidmain(String[]args){Scannersc=newScanner(System.in);intheight1=sc.nextInt();intheight2......
  • Java学习_003 数据输入
    1.数据输入1.2Scanner使用的基本步骤(1)导包importjava.util.Scanner;(2)创建对象Scannersc=newScanner(System.in);(3)接受数据inti=sc.nextInt();1.3实例importjava.util.Scanner;publicclassMain{pub......
  • Java学习_002 案例2:三个和尚
    需求:一座寺庙里住着三个和尚,已知他们的身高分别为150cm、210cm、165cm,请用程序实现获取这三个和尚的最高身高。1publicclassMain{2publicstaticvoidmain(String[]args){3intheight1=150;4intheight2=210;5intheight3......
  • Java对象创建过程,类的生命周期,Java的对象结构
    一、Java对象创建过程1、JVM遇到一条新建对象的指令时,首先去检查这个指令的参数是否能在常量池中定义到一个类的符号引用,然后加载这个类;2、为对象分配内存。一种办法时“指针碰撞”,一种办法是“空闲列表”,最终常用的办法是“本地线程缓冲分配”;3、将除对象头外的对象内存空间初始化......
  • Java学习002__案例1:两只老虎
    需求:动物园里有两只老虎,已知两只老虎的体重分别为180kg、200kg,请用程序实现判断两只老虎体重是否相同。1publicclassMain{2publicstaticvoidmain(String[]args){3intweight1=180;4intweight2=200;5//使用三目运算符实......
  • Java学习_001 常用DOS命令(仅做个人学习记录)
    一些简单的DOS命令:1.DIR显示指定路径上的所有文件或目录的信息格式:DIR[盘符:][路径][文件名][参数]参数:/w:宽屏显示/p:分页显示/a:显示具有特殊属性的文件/s:显示当前目录及其子目录下的所有文件2.CD进入指定目录 3.MD建立文件4.RD删除文件(这个只能删除文件夹且该......
  • JAVA日志技术 & Logback
    前言为什么需要记录日志?我们不可能实时的24小时对系统进行人工监控,那么如果程序出现异常错误时要如何排查呢?并且系统在运行时做了哪些事情我们又从何得知呢?这个时候日志这个概念就出现了,日志的出现对系统监控和异常分析起着至关重要的作用一、日志概括1.了解日志框架JAVA在早期的日......