首页 > 其他分享 >动态类加载

动态类加载

时间:2024-08-22 19:03:58浏览次数:12  
标签:return String 加载 class loadClass 动态 Class name

动态类加载

代码块加载顺序

这里的代码块主要指的是这四种

静态代码块:static{}
构造代码块:{}
无参构造器:ClassName()
有参构造器:ClassName(String name)

我创建两个类
Person.java

public class Person {
public static int staticVar;
public static int id;


static {
    System.out.println("静态代码块");
}

{
    System.out.println("构造代码块");
}

Person(){
    System.out.println("无参构造器");
}
Person(int id){
    System.out.println("有参构造器");
}

public static void staticAction(){
    System.out.println("静态方法");
}
}

Main.java

public class Main {
public static void main(String[] args) {
    new Person();
}
}

他会输出

静态代码块
构造代码块
无参构造器

Person.staticAction();

他会输出

静态代码块
静态方法

Person.id = 1;

他会输出

静态代码块

ok上面的看完了,我们就来获取这个类

Class c = Person.class;

他啥也不输出,所以他没有进行初始化

Class.forName("org.example.Person");

他会输出

静态代码块

说明进行了初始化的操作,我们跟进这个函数

 public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

进入forName0

 private static native Class<?> forName0(String name, boolean initialize,
                                        ClassLoader loader,
                                        Class<?> caller)
    throws ClassNotFoundException;

他第二个参数是看他初不初始化,我们看到上有个另一个forname

public static Class<?> forName(String name, boolean initialize,
                               ClassLoader loader)
    throws ClassNotFoundException
{
    Class<?> caller = null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        // Reflective call to get caller class is only needed if a security manager
        // is present.  Avoid the overhead of making this call otherwise.
        caller = Reflection.getCallerClass();
        if (sun.misc.VM.isSystemDomainLoader(loader)) {
            ClassLoader ccl = ClassLoader.getClassLoader(caller);
            if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                sm.checkPermission(
                    SecurityConstants.GET_CLASSLOADER_PERMISSION);
            }
        }
    }
    return forName0(name, initialize, loader, caller);
}

我们把第二个参数设置为false

    ClassLoader cl = ClassLoader.getSystemClassLoader();
    Class.forName("org.example.Person",false,cl);

他啥也不输出

为什么会这样呢,因为他们都是用了Loader,它是用来初始化的

动态加载字节码

public class Main {
public static void main(String[] args) throws Exception {
    ClassLoader c1 = ClassLoader.getSystemClassLoader();
    Class<?> f = c1.loadClass("org.example.Person");
}
}

我们进入loadClass,本来是会进入Launcher#loadClass但是他没有只传一个参数的所以他会到他的父类URLClassLoader#loadClass,可是还是没有,他会接着往上到SecureClassLoader#loadClass,还是没有最后到ClassLoader#loadClass

public Class<?> loadClass(String name) throws ClassNotFoundException {
    return loadClass(name, false);
}

接着进入Launcher#loadClass

 public Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        int i = name.lastIndexOf('.');
        if (i != -1) {
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                sm.checkPackageAccess(name.substring(0, i));
            }
        }

        if (ucp.knownToNotExist(name)) {
            // The class of the given name is not found in the parent
            // class loader as well as its local URLClassPath.
            // Check if this class has already been defined dynamically;
            // if so, return the loaded class; otherwise, skip the parent
            // delegation and findClass.
            Class<?> c = findLoadedClass(name);
            if (c != null) {
                if (resolve) {
                    resolveClass(c);
                }
                return c;
            }
            throw new ClassNotFoundException(name);
        }

        return (super.loadClass(name, resolve));
    }

然后我们一直走到最后面return (super.loadClass(name, resolve));然后进去ClassLoader#loadClass

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();
                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;
    }
 }

我们来到这个判断

  if (parent != null) {
         c = parent.loadClass(name, false);
                }

因为我们现在是在AppClassLoader,所以他是有parent所以可以进去,然后我们进去ClassLoader#loadClass,然后还是回到了这里,但是ClassLoader变成了ExtClassLoader,接着进行判断,但是他的parent为null,因为BootstrapClassLoader是底层原生代码是 C 语言编写,(这里 null 是因为最上面的 Bootstrap 类是 native 类,也就是之前说过的 C 写的源码,所以为 null。)我们往下走,到了fineClass,进去。会来到URLClassLoader#findClass,可是找到不到,所以就出去这个函数。回到AppClassLoaderloadClass然后往下走到findClass,进入到URLClassLoader#findClass,这部分就是双亲委派,就是先一直往上走到最顶的ClassLoader,然后fineClass看看能不能找到这个类,如果不行就回到下一层看看找不找得到,ExtClassLoader是找不到的,下一层,这个AppClassLoader是可以找到的

protected Class<?> findClass(final String name)
    throws ClassNotFoundException
{
    final Class<?> result;
    try {
        result = AccessController.doPrivileged(
            new PrivilegedExceptionAction<Class<?>>() {
                public Class<?> run() throws ClassNotFoundException {
                    String path = name.replace('.', '/').concat(".class");
                    Resource res = ucp.getResource(path, false);
                    if (res != null) {
                        try {
                            return defineClass(name, res);
                        } catch (IOException e) {
                            throw new ClassNotFoundException(name, e);
                        }
                    } else {
                        return null;
                    }
                }
            }, acc);
    } catch (java.security.PrivilegedActionException pae) {
        throw (ClassNotFoundException) pae.getException();
    }
    if (result == null) {
        throw new ClassNotFoundException(name);
    }
    return result;
}

ok我们进入URLClassLoader#defineClass

 private Class<?> defineClass(String name, Resource res) throws IOException {
    long t0 = System.nanoTime();
    int i = name.lastIndexOf('.');
    URL url = res.getCodeSourceURL();
    if (i != -1) {
        String pkgname = name.substring(0, i);
        // Check if package already loaded.
        Manifest man = res.getManifest();
        definePackageInternal(pkgname, man, url);
    }
    // Now read the class bytes and define the class
    java.nio.ByteBuffer bb = res.getByteBuffer();
    if (bb != null) {
        // Use (direct) ByteBuffer:
        CodeSigner[] signers = res.getCodeSigners();
        CodeSource cs = new CodeSource(url, signers);
        sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
        return defineClass(name, bb, cs);
    } else {
        byte[] b = res.getBytes();
        // must read certificates AFTER reading bytes.
        CodeSigner[] signers = res.getCodeSigners();
        CodeSource cs = new CodeSource(url, signers);
        sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
        return defineClass(name, b, 0, b.length, cs);
    }
}

我们接着进入return defineClass(name, b, 0, b.length, cs);,到了他的父类SecureClassLoader#defineClass

protected final Class<?> defineClass(String name,
                                     byte[] b, int off, int len,
                                     CodeSource cs)
{
    return defineClass(name, b, off, len, getProtectionDomain(cs));
}

然后再到他的父类ClassLoader#defineClass

protected final Class<?> defineClass(String name, byte[] b, int off, int len,
                                     ProtectionDomain protectionDomain)
    throws ClassFormatError
{
    protectionDomain = preDefineClass(name, protectionDomain);
    String source = defineClassSourceLocation(protectionDomain);
    Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);
    postDefineClass(c, protectionDomain);
    return c;
}

然后接着进入Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);

private native Class<?> defineClass1(String name, byte[] b, int off, int len,
                                     ProtectionDomain pd, String source);

他就把字节码加载好了

ClassLoader —-> SecureClassLoader —> URLClassLoader —-> APPClassLoader

loadclass --> findclass --> defineclass

利用URLClassLoader

 URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:///D:\\ideaproject\\dongtaileijiazai\\target\\classes\\")});
    Class<?> c = urlClassLoader.loadClass("org.example.test");
    c.newInstance();

这里的file可以是jar/http/

标签:return,String,加载,class,loadClass,动态,Class,name
From: https://www.cnblogs.com/20031225gbz/p/18374537

相关文章

  • IIS网站图片不能加载
    去掉<addname="misson"path="*"verb="*"modules="IsapiModule"scriptProcessor="C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll"resourceType="File"requireAccess="None&......
  • Idea2024最新版本Mavn加载问题
    Idea2024最新版本Mavn加载问题简述由于公司项目多,各个项目不一致版本,有的jdk1.8、有jdk11,最近由于工作安排,我将从转到其它项目里面。至此开启了,我的新老项目编译不通过之路。mavenclean项目错误并将加载巨慢java.lang.OutOfMemoryError:GCoverheadlimitexceeded尝试......
  • 动态规划引入 Day 1
    动态规划总所周知,动态规划是一个肥肠重要的一个东西(对于算法竞赛而言)……So,我们开始讲动态规划。用的是Luogu官方题单:https://www.luogu.com.cn/training/211#problems以下也会依此顺序来讲解。。。引子Problem1https://www.luogu.com.cn/problem/P1216[USACO1.5][I......
  • 动态化-鸿蒙跨端方案介绍
    一、背景......
  • 动态规划
    问题实例:跳格子小明和朋友玩跳格子游戏,有n个连续格子,每个格子有不同的分数,小朋友可以选择以任意格子起跳,但是不能跳连续的格子,也不能回头跳;给定一个代表每个格子得分的非负整数数组,计算能够得到的最高分数。输入描述:给定一个数列,如:12311<nums.length<1000<=nums[i]<=1000......
  • element plus el-table 合并行或列(根据列表数据动态合并第一列重复的单元格)
    http://element-plus.org/zh-CN/component/table.html#%E5%90%88%E5%B9%B6%E8%A1%8C%E6%88%96%E5%88%97 <scriptsetup>import{onMounted,ref}from'vue'import'./index.css'constobjectSpanMethod=({row,column,rowInde......
  • WPF中如何使用后台代码动态创建数据模板(DataTemplate)
    数据模板回顾 在WPF中数据模板可以控制数据的呈现方式。对于一些简单的数据,例如一个string,一个int,在显示时,无须额外控制。但是对于复杂数据类型,就需要使用数据模板来控制数据的呈现方式。 一个很简单的例子假设我们定义了一个学生类1publicclassStudent2......
  • 动态树笔记
    不知道“树链剖分”、“全局平衡二叉树”等应不应该归类到“动态树”里面...解决动态树问题的本质是将原树映射到一个高度为\(O(\logn)\)的树上。树链剖分主要是重链剖分,具体略.支持:链修改链查询子树修改子树查询这里的修改、查询需要满足可以用数据结构维护.一般......
  • 【JVM-类加载器】
    在JVM中主要有以下几种类加载器:一、启动类加载器(BootstrapClassLoader)作用:负责加载JVM自身需要的核心类库,这些类库主要是Java安装目录下的jre/lib目录中的类。例如,加载Java的核心类库如java.lang包下的类,包括Object、String等。特点:由C/C++语言实现......
  • 算法笔记|Day32动态规划V
    算法笔记|Day32动态规划V※※※※※完全背包问题理论基本题目描述题目分析采用一维数组(滚动数组)☆☆☆☆☆leetcode518.零钱兑换II题目分析代码☆☆☆☆☆leetcode377.组合总和Ⅳ题目分析代码☆☆☆☆☆KamaCoder57.爬楼梯(待补充)题目分析代码※※※※※完全......