java类加载机制

深入理解Java类加载机制 Java的类加载机制是JVM实现的重要部分,了解类加载的过程、类加载器的工作原理以及双亲委派模型,有助于我们更好地编写和调试Java程序。希望本文的介绍和示例能够帮助你深入理解Java的类加载机制。如果有任何问题或进一步的讨论,欢迎随时交流。本文已收录于,我的技术网站,有大厂完整面经,工作技术,架构师成长之路,等经验分享。 阅读详情

最近开通了一个订阅号 gexiaolong 在其中记录一些关于java总是记了又忘,忘了又记的一些知识点,所以还是写一篇日志记录一下吧

老规矩,抄作业,关于java的类加载机制的问题也是看了忘,忘了又在看

在此梳理记录一下

说说目前我对java类加载机制的肤浅理解:

就是将java类编译之后对应的的class(字节码)文件加载进入jvm虚拟机并创建该类的Class对象的过程就叫做类的加载吧

具体细节步骤有哪些?
目前能想到的就是,1.找到对应的class文件,解析并校验文件内容是否符合
2.校验通过之后load进jvm虚拟机内存中为当前的java类创建一个相应的Class对象并初始化

​以下查资料,博客,文章等 详述类加载的各个细节步骤:

在此之前先看一下java程序的执行图序
在这里插入图片描述

JVM内存:
在这里插入图片描述

一、类加载概念

java虚拟机将Class字节码文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的java类型

.class文件有类装载器装载后,在jvm中将形成一份描述Class结构的元信息对象,通过该类的Class对象可以获取该类的结构信息,如构造函数,属性和方法等,java允许通过该类的Class对象的元信息间接调用Class对象的功能

二、类加载过程

工作机制
类装载器寻找字节码文件,并构造出类在jvm内部表示的对象组件
类装载器把一个类装入jvm中,要经过

(1)装载loading:查找和导入相应的class文件
(2)链接linking:把类的二进制数据合并到JRE中
2.1 校验-verification 检查载入class文件数据的正确性
2.2 准备-preparation 给类的静态变量分配存储空间 赋默认值
2.3 解析-resolution 将符号引用转成直接引用
(3)初始化initializing:对类的静态变量,静态代码块执行初始化操作 赋初始值

加载.class文件的方式有:
1.本地系统中直接加载
2.通过网络下载.class文件
3.从zip,jar等归档文件中加载.class文件
4.从专有数据库中提取.class文件
5.将java源文件动态编译为.class文件

2.1装载
jvm在类的加载阶段需要完成以下三件事情:
1.通过一个类的全限定名称来获取定义此类的二进制字节流
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3.在java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口

类的加载可以由系统提供的类加载器完成,也可以由用户自定义的类加载器完成(可在自定义的类加载器中控制字节流的获取方式)
加载完成,虚拟机外部的字节流按照虚拟机所需的格式存储在方法区之中,且在java堆中创建一个java.lang.Class类的对象,通过该对象访问方法区中的数据

2.2链接阶段

验证–>准备–>解析–>初始化
验证:
1.文件格式验证 CA FE BA BE
2.元数据验证
3.字节码验证
4.符号引用验证

准备: 为类变量分配内存并设置类变量的初始值【零值】
1.只包含static 修饰的类变量,会分配在方法区
2.不包含使用final修饰的static,因为final在编译的时候就会分配了,

解析:解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程
符号引用(Symbolic Reference) : 以一组符号来描述所引用的目标,
直接引用(Direct Reference): 可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用与虚拟机实现的内存布局相关,同一个符号引用在不同的虚拟机实例上翻译出来的直接引用一般不相同,若存在了直接引用,则引用的目标必定已经在内存中存在的

1). 类或者接口的解析:判断所要转化成的直接引用是对数组类型,还是普通的对象类型的引用,从而进行不同的解析
2). 字段解析:对字段进行解析时,会先在本类中查找是否包含有简单名称和字段描述符都与目标相匹配的字段,若果有,则查找结束;如果没有,则会按照继承关系从上往下递归搜索该类所实现的各个接口和它们的父接口,还没有,则按照继承关系从上往下递归搜索其父类,直至查找结束
3). 类方法解析: 对类方法的解析与对字段解析的搜索步骤差不多,只是多了判断该方法所处的是类还是接口的步骤,且对类方法的匹配搜索,是先搜索父类,再搜索接口
4). 接口方法解析:与类方法解析步骤类似,只是接口不会有父类,因此只递归向上搜索父接口就行

解析通常主要针对类、接口、字段、类方法、接口方法、方法类型等。对应常量池中的
CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info

2.3初始化
初始化阶段就是开始执行类中定义的java程序代码
执行类构造器方法()
初始化为类的静态变量赋正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化,在java中对类变量进行初始化的两种方式:

1.声明变量时指定初始值
2.使用静态代码块为类变量指定初始值

三、JVM初始化步骤:

1.若该类还没有被加载和连接,则优先加载并连接该类
2.若该类的直接父类还没有被初始化,则先初始化其直接父类
3.若该类中有初始化语句,则系统依次执行这些初始化语句

初始化阶段执行类构造器方法() 的过程

1.类构造器方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块) 中的语句合并产生的,编译器收集的顺序由语句在源文件中出现的顺序所决定

2.类构造器方法与类的构造函数不同,它不需要显示地调用父类构造器,虚拟机会保证在子类的类构造器方法执行之前,父类的类构造器方法已经执行完毕,因此在虚拟机中第一个执行的类构造器方法的类是java.lang.Object

3.由于父类的类构造器方法先执行,所以父类中定义的静态语句块要优先于子类的变量赋值操作

4.类构造器方法对于类或者接口 不是必须的,若一个类中没有静态语句块 也没有对变量的赋值操作,那么编译器可以补位该类生成类构造器方法

5.接口中可能会有变量的赋值操作,因此接口也会生成类构造器方法,但是接口与类不同,执行接口的类构造器方法不需要先执行父接口的类构造器方法。只有当父接口中定义的变量被使用时,父接口才会被初始化。另:接口实现类在初始化时也不会执行接口的类构造器方法

6.虚拟机会保证一个类的类构造器方法在多线程环境中被正确地加锁和同步。若有多个线程同时初始化一个类,那么只会有一个线程去执行这个类的类构造器方法,其他线程都需要阻塞等待,直到活动线程执行类构造器方法完毕。
? 思考,如果 这个线程已经执行完该类构造器方法构建类完成,还需要其他线程再调用该类构造器方法吗?

类的初始化
虚拟机规范并未强行约束,初始化具体细节交由虚拟机的具体实现自由把握。但是对于初始化阶段虚拟机严格规范了以下的几种情况,如果类未初始化 则会对类进行初始化

  • 1.创建类的实例
    2.访问类的静态变量(除常量[被final修饰的静态变量]) 原因:常量是一种特殊的变量,在编译器把他们当做值(value) 【直接初始化了变量名和对应的值在字节码中】 而不是域(field)来对待。 若代码中用到了常变量(constant
    variable),编译器并不会生成字节码来从对象中载入域的值,而是直接把这个值插入到字节码中。这是一种有用的优化,但是如果需要改变final域的值,那么每一块用到这个域的代码都需要重新编译

    3.访问类的静态方法
    4.反射如(Class.forName(“my.gexl.Test”))
    5.当初始化一个类时,发现其父类还未初始化,则先触发父类的初始化
    6.虚拟机启动时,定义了main()方法的那个类先初始化

以上为类的“主动引用”,均会触发类的初始化,还有一些“被动引用”的情况如:接口的加载过程和类的加载过程中,接口中不能使用static{}块,当一个接口初始化时,并不要求其父接口全部都完成初始化,只有在真正使用到父接口时(引用接口中定义的常量)才会初始化。

  • 被动引用如下:
    1.子类调用父类的静态变量,子类不会被初始化。只有父类被初始化,对于静态字段,只有直接定义这个字段的类才会被初始化
    2.通过数组定义来引用类,不会触发类的初始化
    3.访问类的常量[被final修饰的类的常量],不会初始化类
    若非被final修饰的类的常量,使用时还是会触发类的初始化
    以下为测试代码:
public class ClassLoadTest {

    public static void main(String[] args) {
     	ConstClass [] subs = new ConstClass[10];
        System.out.println(ConstClass.v);
        System.out.println(ConstClass.HELLOWORLD);
    	// 输出结果为:
    	// 21
		// ConstClass init
		// helloworld
    }
}
class ConstClass {

    public static final int v = 21;
    static {
        System.out.println("ConstClass init");
    }
    public static String HELLOWORLD = "helloworld";
}

*类的初始化顺序 * [感觉这块的表达太书面化,写的有点晦涩,跟上面初始化的主动引用和被动引用所触发的初始化,表达的意思结果差不多,运行上面的代码便可理解的事情,个人建议此处可略过,感兴趣的可以读一读]

在java语言规范中, 域(fields,静态的或是非静态的)、块(block静态的或是非静态的)、不同类(子类和超类) 和不同的接口(子接口,实现类和超接口)的初始化顺序也很重要。
需要遵循如下规则

  1. 类从顶至底的顺序初始化,所以声明在顶部的字段要早于底部的字段初始化
  2. 超类早于子类和衍生类的初始化
  3. 如果类的初始化是由于访问静态域而触发,那么只有声明静态域的类才被初始化,而不会触发超类或者子类的初始化
  4. 初始化即使静态域被子类或子接口或者它的实现类所引用
  5. 接口初始化不会导致父接口的初始化
    6.静态域的初始化是在类的静态初始化期间,非静态域的初始化是在类的实例创建期间,静态域的初始化在非静态域之前
    7.非静态域通过构造函数初始化,子类在做任何初始化之前构造器会隐含地调用父类的构造器,它保证了非静态域或实例变量(父类) 初始化早于子类

四、类加载器

由同一个类加载器加载 且来源于同一个Class文件的两个类才是相等的

双亲委派模型
jvm虚拟机角度来说,一种是启动类加载器(Bootstrap ClassLoader),该类加载器使用C++语言实现,属于虚拟机自身的一部分;另外一种是由其他类加载器,是由java语言实现的,独立于jvm外部,并且全部继承自抽象类java.lang.ClassLoader

BootStrap ClassLoader 由C++语言实现 启动 加载 /lib/rt.jar
Extension ClassLoader 扩展类加载器 jre/lib/ext.jar
Application ClassLoader 应用类加载器 加载classpath:
Custom ClassLoader 自定义类加载器

  public class Test {
  		public static void main(String[] args) {
			// Test的类加载器
        	System.out.println(Test.class.getClassLoader());
			// Test的类加载器的父 类加载器
        	System.out.println(Test.class.getClassLoader().getParent().getClass());
			// Test的类加载器的父类加载器的 加载器
        	System.out.println(Test.class.getClassLoader().getParent().getClass().getClassLoader());
			// Test的类加载器的父 类加载器的父 类加载器
        	System.out.println(Test.class.getClassLoader().getParent().getParent());
    }
输出结果为:
sun.misc.Launcher$AppClassLoader@644d46    --> 对应 AppClassLoader 
sun.misc.Launcher$ExtClassLoader@ed1f14   ---> 对应 ExtClassLoader
null									 ---> 对应 BootStrapClassLoader
null									 ---> 对应 BootStrapClassLoader

双亲委派类加载模型工作过程:
关于双亲委派的说明:[基于安全因素的考虑 比如再写一个名字为java.lang.String的类]
该模型要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器(parent属性)。子类加载器和父类加载器不是以继承关系来实现的,而是通过组合(Composition)关系来复用父加载器的代码

双亲委派类加载机制:如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的加载器都是如此,因此所有的类加载器请求都会传给顶层的启动类加载器,只有当父类加载器反馈自己无法完成该加载请求(父类加载器未找到对应的类),子加载器才会尝试自己去加载

在java源码中基于类加载的具体实现如下
rt.jar 包中的java.lang.ClassLoader类中

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            // 查找加载 class文件
            Class<?> c = findLoadedClass(name);
            // 
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        // 优先由 父加载器加载
                        c = parent.loadClass(name, false);
                    } else {
                    	// parent == null 时由 BootstrapClassLoader 加载
                        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();
                    // 若父类加载器 未加载成功 则由自身查找加载
                    
                    c = findClass(name);

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

由代码看出,双亲委派模型通过locadClass() 方法来实现,
先检查是否已经被加载过,如果没有则调用父加载器的loadClass() 方法,如果父类加载器为空则默认使用启动类加载器加载,如果父类加载器加载失败,则抛出ClassNotFoundException,然后调用自己的findClass()方法进行加载

自定义类加载器
若要实现自定义的类加载器,需要继承自 java.lang.ClassLoader 类,并且重写其中的findClass() 方法即可。
java.lang.ClassLoader类的基本职责就是根据一个指定的类名称,找到或者生成与其对应的字节代码,然后从这些字节代码中定义一个Java类,即java.lang.Class类【对应该java】的一个Class实例。除此之外ClassLoader 还负责加载Java应用所需要的资源,如图像文件和配置文件等,ClassLoader中与加载类相关的方法如下:
方法说明
getParent() 返回该类加载器的父 类加载器

loadClass(String name) 加载名称为二进制名称为name的类 返回的结果是java.lang.Class类的实例

findClass(String name) 查找名称为name的类,返回的结果为java.lang.Class类的实例

findLoadedClass(String name) 查找名称为name的已经加载过的类,返回结果是java.lang.Class类的实例

resolveClass(Class<?> c) 连接指定的Java类

自jdk1.2 之后双亲委派模型已经被引入到类加载体系中,自定义的类加载器只需要重写findClass() 方法即可

示例代码:
User2.class 文件

public class ClassLoaderTest {

    public static void main(String[] args) throws Exception {
        MyClassLoader myClassLoader = new MyClassLoader("aaaa");
		Class cl = myClassLoader.loadClass("com.gexl.bean.User2");
        System.out.println(myClassLoader.getClass().getClassLoader());
        System.out.println(myClassLoader.getParent());
        Object user2 = cl.newInstance();
        System.out.println("user2=="+user2);
        System.out.println(user2.getClass().getClassLoader());
        // 调用 User2 中的 say方法 输出
        cl.getMethod("say",null).invoke(user2,null);
    }
		// 输出结果为:
		进入自定义的类加载器name=com.gexl.bean.User2
		defineClassName==com.gexl.bean.User2
		sun.misc.Launcher$AppClassLoader@644d46
		sun.misc.Launcher$AppClassLoader@644d46
		user2==com.gexl.bean.User2@19d7047
		MyClassLoader@29724f
		Hello User2..
		---------------
}

class Animal {
    public void say() {
        System.out.println("Hello world");
    }
}

class MyClassLoader extends ClassLoader{

     // 类加载器的名字
    private String name;
    // 类存放的路径
    private String path = "D:\\temp";

    MyClassLoader(String name) {
        this.name = name;
    }

    MyClassLoader(ClassLoader parent,String name) {
        super(parent);
        this.name = name;
    }

    /**
     * 重写findClass 方法
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        System.out.println("进入自定义的类加载器name="+name);
        String fileName = path.concat(File.separator).concat(name.replace(".",File.separator)).concat(".class");
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(new File(fileName));
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
                int b = 0;
                while ((b = fis.read()) != -1) {
                    bos.write(b);
                }
            byte[] data = bos.toByteArray();
            // 此处defineClass 传入的name为类的全限定名com.gexl.bean.User2
            System.out.println("defineClassName=="+name);
            return this.defineClass(name,data,0,data.length);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

建议大家还是要手动撸一遍上面的代码,还是有些地方需要注意的点

1.User2.class 文件不能放在当前项目的目录下,我放在了D:\temp\com\gexl\bean 文件夹下
如果放在当前项目的目录下会被否则会被sun.misc.Launcher$AppClassLoader 加载到jvm中
不会通过我们自定义的类加载器来加载
2.defineClass 方法 传递的name文件名需要是类的全限定性名称,即com.gexl.bean.User2格式的,因为 defineClass 方法是按这种格式进行处理的 否则会报错:: Exception in thread “main” java.lang.NoClassDefFoundError: D:\temp\com\gexl\bean\User2/class (wrong name: com/gexl/bean/User2)
at java.lang.ClassLoader.defineClass1(Native Method)

动态加载Jar && ClassLoader隔离问题

动态加载Jar:

URL[] urls = new URL[]{new URL("file:lib\jar1.jar)}
URLClassLoader loader = new URLClassLoader(urls,parentLoader);

加载libs下面的jar1.jar , 其中parentLoader 就是上面1中的parent,可以为当前的ClassLoader

此处我暂时也是有点不太清楚是怎么回事的。先暂时略过吧,写了这么多现在脑子有点不太转圈了

ClassLoader 的隔离问题
如果有两个类的包名和类名都相同的情况 PackageName+ClassName.
都相同的话,但是由两个不同的ClassLoader 加载【ClassLoader id】进入虚拟机
那么这两个类之间是无法强行转换的,这个就叫做ClassLoader 隔离

解决办法,只保留一个类,指定同一个parentClassLoader 来加载此类就ok了

关于类的加载机制,细节的内容还是挺多的,有些东西也是不太容易记住的,建议还是要自己手撸一遍代码,跑一跑测试一下,写了将近1万字了,就先这样吧,若有一些疏漏错误,希望可以与大家一起讨论

具体在往jvm虚拟机内部的一些native方法相关的cpp源码文件,暂时还未来的及学习分析,后续有时间的话在接着深入学习之后,再来与大家分享吧。

Java 类加载机制(超详细版) JVM 通过类的全限定名(比如找到对应的 .class 字节码文件,将其读入内存,并生成一个代表该类的对象(存储在方法区,是类的 “元数据载体”)。默认类加载器只能加载 “特定路径” 的类,若需要加载 “加密字节码”“网络字节码”“数据库存储的字节码”,则需要自定义类加载器。继承类(或,简化 URL 路径加载);重写方法(核心:实现字节码的读取和转化);调用方法(将字节数组转为Class对象,由父类提供,不可重写)。不要重写方法(默认实现双亲委派逻辑),若重写可能破坏双亲委派模型; 阅读详情

相关推荐

别再到处找模板了!手把手教你用Vue3+Element Plus搭建一个‘能跑起来’的管理后台原型

本文详细介绍了如何利用Vue3和Element Plus在72小时内快速搭建一个功能完整的管理后台原型。从环境准备到项目获取、依赖安装、原型定制、数据模拟以及构建优化,手把手教你打造一个可直接演示的后台系统,特别适合创业者快速验证产品逻辑。

weixin_26854555的博客 182

Java类的加载机制

1、加载的生命周期类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Intialization)、使用(Using)、卸载(Unloding)7个阶段。其中验证、准备、解析 3个部分统称为链接(Linking)。加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之

u010257931的博客 3999

EMC测试案例分析——晶振对辐射发射的影响

本文分析了某产品350MHz辐射发射超标问题,发现源头是50MHz晶振的7次谐波通过连接器泄漏。主要原因是:1)防水非导电垫圈形成屏蔽缝隙;2)晶振下方地平面不完整且信号线穿过;3)晶振离接口过近。改进措施包括:完善晶振下方地平面、增大晶振与接口距离、使用导电密封圈等。最终辐射降低10dB以上达标。文章总结了晶振EMC设计要点:保持地平面完整、远离接口、外壳接地、合理布局滤波电路等,并强调防水与屏蔽的协调统一。

u012526819的博客 669

一文搞懂Java类加载机制

初始化阶段是执行类构造器()方法的过程。

BarackYoung的博客 5431

从零配置华为S5720交换机VLAN:Web界面与命令行双模式详解(附拓扑图)

本文详细解析华为S5720交换机VLAN配置的全过程,涵盖Web界面与命令行(CLI)双模式操作指南。从基础环境准备到多交换机环境配置同步,特别针对S5720-52X系列交换机的VLANif接口、端口分配策略及交换机堆叠技术进行深入讲解,并附实用拓扑图与配置示例,助力企业网络管理员高效完成VLAN部署。

happy2的博客 1371

Labview程序框架介绍

当掌握LabVIEW基础知识并达到,理解单个小型模块程序会相对轻松。而若想进一步探索大型程序,就必然需要了解程序框架相关内容。LabVIEW常用的程序架构包括等。在多年工作中,我接触过的众多高级工程师所开发的大型程序,基本都基于这些架构搭建。接下来,将为大家详细介绍这些框架。

Misterlhw的博客 4620

Java类加载机制

Java类加载机制 类加载的时机 隐式加载 new 创建类的实例, 显式加载:loaderClass,forName等 访问类的静态变量,或者为静态变量赋值 调用类的静态方法 使用反射方式创建某个类或者接口对象的Class对象。 初始化某个类的子类 直接使用java.exe命令来运行某个主类 类加载的过程 我们编写的java文件都是保存着业务逻辑代码。java编译器将 .java 文件编译成扩...

清风博客 7万+

如何利用Arcgis进行地统计学分析(三):空间插值方法选择与优化

本文深入探讨了在Arcgis中进行地统计学分析时,如何根据探索性数据分析(EDA)结果科学选择与优化空间插值方法。文章对比了IDW、RBF、克里金等主流方法的适用场景与核心参数,并通过实战案例详解了从数据诊断到模型调优的完整流程,强调结合半变异函数与趋势分析进行“对症下药”,以提升插值结果的精度与可靠性。

weixin_29281915的博客 121

JAVA类加载机制

​ 虽然经理在OA系统里看不到SalaryCaler类的源码了,但是通过OA系统的源码最终还是可以找到这个jar包。那么就可以对jar包进行反编译,查看到jar包对应的源码了。所以,老王还需要考虑如何对class文件进行代码混淆,让经理无法反编译出源码。简单一点的,将class文件的后缀改一下,从.class转为.myclass。就像大家把游戏软件改成.txt结尾一样。只是修改后缀,那么经理还可以把后缀改回来再反编译。所以稳妥一点的方法,是要改一改class文件当中的二进制内容。

博客 1247

uniapp - 详解使用高德地图在地图上实现绘制边界/点聚合/行政区域高亮等功能,Uniapp高德地图点聚合标记及绘制点线面示例代码(全端兼容H5网页、小程序、安卓app、苹果app、nvue)

uni-app,h5移动端网页,微信小程序,支付宝小程序,Android安卓,苹果ios,app,nvue,高德地图,uniAPP高德地图实现点聚合,地图区域描边、点标记、点信息详情弹窗,实现绘制边界区域,uniapp H5使用高德地图实现点聚合、行政区域高亮,实现高德地图的marker聚合功能,高德地图进行marker标点,点信息展示,点击标记点弹出对话框,点击聚合点后显示信息模态框,打标点,【Uniapp】高德地图的接入自定义标点与信息窗体使用,绘制行政区域边界,绘制多边形,电子围栏,高德行政区划边界,

✅ 精选推荐文章 1万+

QT+QGIS跨平台编译(基于Qt,采用一套代码、一套框架,完成QGIS第三方库、核心库、应用程序的跨平台编译)

QT+QGIS跨平台编译。 基于Qt,采用一套代码、一套框架,完成QGIS第三方库、核心库、应用程序的跨平台编译。

LuckyHanMo的博客 4379

【Java】类加载机制

本文探讨 Java 类加载机制的各个方面,包括类加载的过程、类加载器的作用以及类加载的触发条件等

qq_45797138的博客 914

【目标检测-YOLO】YOLOv5-v5.0-yolov5s网络架构详解(第一篇)

源码:GitHub - ultralytics/yolov5 at v5.0 由于YOLO v5 代码库在持续更新,如上图,有多个版本,每个版本的网络结构不尽相同。以下内容以 v5.0 为准,网络结构选用 yolov5s。 为了方便画图和理解网络结构,选用可视化工具:Netron 网页版进行可视化, 然后使用PPT作图。 在Releases · ultralytics/yolov5 · GitHub找到 v5.0中的Assets 中的yolov5s.pt并下载该权重。 下图为直接......

博观约取,厚积薄发 2万+

Java 类加载机制

Java 类加载机制是 JVM 的核心组成部分,负责将类的字节码文件加载到内存中并转换为可用的类对象。类加载过程包括加载、验证、准备、解析和初始化五个阶段,最终形成可被虚拟机直接使用的 Java 类型。Java 提供了三种系统级类加载器(Bootstrap、Extension、Application),并采用双亲委派模型来确保类加载的安全性和一致性,避免重复加载和核心类库被篡改。自定义类加载器可以通过继承 ClassLoader 来实现特殊需求,如热部署或远程加载。类卸载则依赖于垃圾回收机制,只有在特定条件

红血哥 1039

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

【JAVA】类加载机制

​ 虽然经理在OA系统里看不到SalaryCaler类的源码了,但是通过OA系统的源码最终还是可以找到这个jar包。那么就可以对jar包进行反编译,查看到jar包对应的源码了。所以,老王还需要考虑如何对class文件进行代码混淆,让经理无法反编译出源码。简单一点的,将class文件的后缀改一下,从.class转为.myclass。就像大家把游戏软件改成.txt结尾一样。只是修改后缀,那么经理还可以把后缀改回来再反编译。所以稳妥一点的方法,是要改一改class文件当中的二进制内容。

2301_79456272的博客 1384

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Java 类加载机制详解

Java类加载机制是Java运行时的核心,包含加载、验证、准备、解析、初始化等阶段,遵循双亲委派模型确保安全性和唯一性。类加载器分为启动类、扩展类、应用类和自定义类加载器,自定义类加载器可实现热部署和隔离。常见问题包括类冲突和加载异常,可通过调整类路径或隔离解决。该机制在热部署、插件化等场景有重要应用,深入理解有助于排查问题和优化性能。

weixin_43114485的博客 2007

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

图解Java类加载机制

前言 类加载的概述 双亲委派加载机制 类加载的隔离机制 contextClassLoader SPI用处 找文件用处 类加载的顺序 顺序概述 类加载的一般方式 类加载的触发点 类的实例化 附录前言网上有很多的Java类加载机制的介绍, 但是对于初学者而言看起来都太过于深疏, 因此在本文用图解和例子的方式为本文的读者介绍Java的类加载机制。类加载的概述双亲委派加载机制委派模型介绍: 双亲委派模型

平菇虾饺 9085

Java的类加载器和类加载机制详解

详细介绍了Java的类加载器和类加载机制。Java的Class(类)加载器,主要工作在Class加载的“加载阶段”,其主要作用是从系统外部获取Class的二进制数据流。

终生学习践行者 2733

Java中的类加载机制

Java的类加载机制主要是为了在运行时动态加载类。这种机制不仅使Java程序更灵活,而且显著提高了内存利用效率。类加载器(ClassLoader)在Java虚拟机(JVM)中扮演着至关重要的角色,负责从不同的资源(如文件系统、网络等)加载类文件,并将它们转换为JVM可以执行的字节码。有时候,开发者需要定制自己的类加载器以满足特定需求。自定义类加载器需要继承类,并重写findClass方法。这个方法负责从自定义的资源(如网络、数据库)中加载类的字节码,并将其转换为Class对象。

weixin_46372265的博客 836
上一篇: 去除WinRar压缩 迷你页
下一篇: Spring中BeanFactory与FactoryBean的区别
xiaolong_java
博客等级 码龄12年 1粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值