如果我有一个内部类声明,例如:
Class A {
public static class B {
}
}
接着:
Class<?> implClass = getClass().getClassLoader().loadClass("A");
A$B内部类是否也会被加载? 如果B内部类没有声明为“static”,会发生什么?
如果我有一个内部类声明,例如:
Class A {
public static class B {
}
}
接着:
Class<?> implClass = getClass().getClassLoader().loadClass("A");
A$B内部类是否也会被加载? 如果B内部类没有声明为“static”,会发生什么?
代码编译后,内部类就不存在了。如果查看javac
的结果,你会看到两个文件:
A.class
A$B.class
所以当加载 A
时,并不会加载类 B
,只是恰好在 A
中定义了 B
。
例如,给定以下两个文件:
package kuporific;
public class A {
private static class B {}
private class C {}
}
还有一个 build.gradle
文件(为了方便起见):
apply plugin: 'java'
首先,通过运行gradle build
来构建。然后,解压缩生成的JAR文件(位于build/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;
}
}
注意:
A$B
没有指向其父类 A
的引用,而 A$C
有指向,这是因为前者是静态内部类,后者不是;A$B
和 A$C
现在都是包私有类。这就是非静态内部类能够直接引用其父实例的字段和方法,反之亦然。(在内部类中引用的任何父类私有字段也将变为包私有字段。)
接下来,让我们看看加载类 A
对 A$B
和 A$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"]
-verbose:class
选项会输出JVM加载的所有类(请参见Java - Get a list of all Classes loaded in the JVM)。
在命令行中运行gradle run
(这将运行Main
的main
方法),输出结果(带有我的附加注释)如下:
: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.Main
和 kuporific.A
被加载了,但没有看到 kuporific.A$B
或者 kuporific.A$C
被加载。
A.class
仍然保留 A$B
是 A
的内部类的信息。您可以通过反射访问此信息。 - ghikA
不会加载内部类 B
,无论是静态还是非静态。我已经编辑了我的答案以更好地解释这一点。 - kuporific内部类,即B类
不能存在于父类之外。您需要首先构造父类A类
。
如果您从内部类中删除static,即对于非静态内部类,您需要在内部类构建期间传递父类。
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 });
静态内部类
和非静态内部类
两者。 - rachanapublic class Outer
{
private static final String TEST01 = "I'm TEST01";
static
{
System.out.println("1 - Initializing class Outer, where TEST01 = " + TEST01);
}
public static void main(String[] args)
{
System.out.println("2 - TEST01 --> " + TEST01 );
System.out.println("3 - Inner.class --> " + Inner.class);
System.out.println("5 - Inner.info() --> " + Inner.info() );
}
private static class Inner
{
static
{
System.out.println("4 - Initializing class Inner");
}
public static String info()
{
return "I'm a method in Inner";
}
}
}
System.out.println("5 - Inner.info() --> " + Inner.info() );
1 - Initializing class Outer, where TEST01 = I'm TEST01
2 - TEST01 --> I'm TEST01
3 - Inner.class --> class com.javasd.designpatterns.tests.Outer$Inner
4 - Initializing class Inner
5 - Inner.info() --> I'm a method in Inner
不会,无论哪种情况下嵌套类都不会被加载。