Java ClassLoader 是否装入内部类?

2022-09-01 17:22:01

如果我有一个内部类声明,例如:

Class A {
    public static class B {
    }
}

其次:

Class<?> implClass = getClass().getClassLoader().loadClass("A");

A$B 内部类是否也会被加载?如果 B 内部类未声明为“静态”,该怎么办?


答案 1

一旦代码被编译,就没有内部类这样的东西了。如果您查看 的结果,您将看到两个文件:javac

A.class
A$B.class

所以类在加载时没有加载,只是碰巧在 中定义。BABA


编辑

例如,给定这两个文件,

package kuporific;

public class A {
    private static class B {}
    private class C {}
}

和一个文件(为方便起见):build.gradle

apply plugin: 'java'

首先,通过运行来构建。然后,解压缩生成的 JAR 文件(位于):gradle buildbuild/libs

├── META-INF
│   └── MANIFEST.MF
└── kuporific
    ├── A$B.class
    ├── A$C.class
    └── A.class

打开每个文件(例如在 IntelliJ 中),将显示编译器执行的操作:

  • A.class:

    package kuporific;
    
    public class A {
        public A() {
        }
    
        private class C {
            public C() {
            }
        }
    
        private static class B {
            public B() {
            }
        }
    }
    
  • A$B.class:

    package kuporific;
    
    class A$B {
        private A$B() {
        }
    }
    
  • A$C.class:

    package kuporific;
    
    import kuporific.A;
    
    class A$C {
        private A$C(A this$0) {
            this.this$0 = this$0;
        }
    }
    

请注意,

  1. A$B没有对其父级 的引用,而 确实如此。这是因为前者是静态的内部类,而后者不是,并且AA$C
  2. 两者现在都是打包私有类。A$BA$C

这就是非静态内部类能够直接引用其父实例的字段和方法的方式,反之亦然。(在内部类中引用的父类的任何私有字段也都将成为包私有的。

接下来,让我们看看加载类对 和 有什么影响。AA$BA$C

首先,添加以下 Java 类:

package kuporific;

public class Main {
    public static void main(String[] args) throws ClassNotFoundException {
        Main.class.getClassLoader().loadClass("kuporific.A");
    }
}

现在将以下内容添加到文件中:build.gradle

apply plugin: 'application'
mainClassName = 'kuporific.Main'
applicationDefaultJvmArgs = ["-verbose:class"]

输出由 JVM 加载的所有类(请参阅 Java - 获取 JVM 中加载的所有类的列表)。-verbose:class

在命令行上运行(运行 );输出(带有我添加的注释)是gradle runmainMain

:compileJava
:processResources UP-TO-DATE
:classes
:run
[Opened /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Object from /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/jre/lib/rt.jar]
# Lots of omitted output...
[Loaded kuporific.Main from file:/tmp/build/classes/main/]
        ^ here!
[Loaded sun.launcher.LauncherHelper$FXHelper from /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Class$MethodArray from /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded kuporific.A from file:/tmp/build/classes/main/]
        ^ here!
[Loaded java.lang.Shutdown from /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/jre/lib/rt.jar]
[Loaded java.lang.Shutdown$Lock from /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/jre/lib/rt.jar]

BUILD SUCCESSFUL

Total time: 6.502 secs

我们可以看到何时加载和被加载,而我们看不到任何一个或正在加载。kuporific.Mainkuporific.Akuporific.A$Bkuporific.A$C


答案 2

内部类即不能存在于父类之外。您需要首先构造父类。class Bclass A

如果你从你的内部类中删除静态,即非静态内部类,你需要在构造内部类时传递父类。

Object a = Class.forName("A").newInstance();    //object of outer class

//object of inner class
Object b = implClass.getDeclaredConstructor(new Class[] { a.getClass() })
        .newInstance(new Object[] { a });

推荐