简体   繁体   English

Java ClassLoader是否加载内部类?

[英]Does the Java ClassLoader load inner classes?

If I have a inner class declaration such as: 如果我有一个内部类声明,例如:

Class A {
    public static class B {
    }
}

followed by: 其次是:

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

Will the A$B inner class be loaded as well? A $ B内部类也会被加载吗? What if the B inner class was not declared as "static" ? 如果B内部类没有被声明为“静态”怎么办?

Once the code is compiled, there's no such thing as an inner class . 编译代码后, 就没有内部类 If you look at the results of javac , you'll see two files: 如果你看一下javac的结果,你会看到两个文件:

A.class
A$B.class

So class B is not loaded when A is loaded, B just happens to be defined in A . 因此,在加载A时不加载B类, B 恰好A定义。


Edit 编辑

For example, given these two files, 例如,给定这两个文件,

package kuporific;

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

and a build.gradle file (for convenience): build.gradle文件(为方便起见):

apply plugin: 'java'

First, build by running gradle build . 首先,通过运行gradle build Then, unzip the resulting JAR file (located in build/libs ): 然后,解压缩生成的JAR文件(位于build/libs ):

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

Opening each file (in IntelliJ, for example), reveals what the compiler has done: 打开每个文件(例如,在IntelliJ中),显示编译器已完成的操作:

  • A.class : A.class

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

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

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

Notice that 请注意

  1. A$B does not have a reference to its parent, A , while A$C does. A$B没有对其父A的引用,而A$C则没有。 This is because the former is a static inner class, and the latter is not, and 这是因为前者是静态内部类,而后者不是,而且
  2. both A$B and A$C are now package private classes. A$BA$C现在都是包私有类。

This is how non-static inner classes are able to directly reference their parent instance's fields and methods, and vice versa. 这就是非静态内部类能够直接引用其父实例的字段和方法的方式,反之亦然。 (Any private fields of the parent class referenced in an inner class are made package private as well.) (内部类中引用的父类的任何私有字段也都是私有的。)

Next, let's see what effect loading class A has on A$B and A$C . 接下来,让我们看看加载A类对A$BA$C

First, add the following Java class: 首先,添加以下Java类:

package kuporific;

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

Now add the following to the build.gradle file: 现在将以下内容添加到build.gradle文件中:

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

The -verbose:class outputs all classes that are loaded by the JVM (see Java - Get a list of all Classes loaded in the JVM ). -verbose:class输出JVM加载的所有类(请参阅Java - 获取 JVM中加载的所有类的列表 )。

Run gradle run on the command line (which runs the main method of Main ); 在命令行上运行gradle run (运行Mainmain方法); the output (with my added notes) is 输出(带有我添加的注释)是

: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

We can see when kuporific.Main and kuporific.A were loaded, and we do not see either kuporific.A$B or kuporific.A$C being loaded. 我们可以看到当kuporific.Mainkuporific.A被加载时,我们看不到kuporific.A$Bkuporific.A$C被加载。

Inner classes ie class B cannot exist outside the parent class. 内部类即class B不能存在于父类之外。 You need to construct the parent class ie class A first. 您需要首先构造父类,即class A

and if you remove static from your inner class ie for non-static inner class , you need to pass the parent class in during construction of the inner class. 如果从内部类中删除静态,即对于非静态内部类 ,则需要在构造内部类时传递父类。

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

不,在任何一种情况下都不会加载嵌套类。

A ClassLoader will not load a class, unless it was requested (eg using loadClass ). ClassLoader不会加载类,除非它被请求(例如使用loadClass )。 While loading a class, a ClassLoader will request referenced classes. 在加载类时, ClassLoader将请求引用的类。

As your class A does not reference AB , AB will not be loaded, whether it is static or not. 由于您的A类不引用AB ,因此不会加载AB ,无论它是否为静态。 (To be honest, A does reference AB , but not in a manner causing the ClassLoader to load AB .) (老实说, A确实引用了AB ,但没有引起ClassLoader加载AB 。)

If you add a field of type AB or use the type AB in another way (eg as a method return type), it will actually be referenced in A.class and therefore be loaded. 如果添加类型的字段AB或使用类型AB以另一种方式(例如,作为方法的返回类型),它实际上将在引用A.class并因此被载入。

The code below is runnable and can illustrate some of the other answers: 下面的代码是可运行的,可以说明其他一些答案:

public 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";
       }
    }
}

Please, pay attention to the sequence numbers, especially in this line: 请注意序列号,特别是在这一行:

System.out.println("5 - Inner.info() --> " + Inner.info() );

When you run the program you will see the following result on the console: 运行程序时,您将在控制台上看到以下结果:

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

A little more detail for each step: 每个步骤的更多细节:

1 - 'Outer' is initialized when you Run the program. 1 - 运行程序时初始化“外部”。 The static variable TEST01 is initalized before static block. 静态变量TEST01在静态块之前初始化。 Inner is not initialized. 内部未初始化。

2 - The 'main' method is called and shows the value of 'TEST01'; 2 - 调用'main'方法并显示'TEST01'的值; then, 然后,

3 - The System.out shows reference to 'Inner'. 3 - System.out显示对'Inner'的引用。 Inner is not initialized , but it was loaded (that's why it has reference in the memory model). Inner未初始化 ,但已加载(这就是它在内存模型中有引用的原因)。

4 - Here's the most interesting part. 4 - 这是最有趣的部分。 Because the System.out needs to access the 'info()' method in 'Inner' ( Inner.info() ), the 'Inner' class should be initialized before returning the result of the 'info()' method. 因为System.out需要访问'Inner'(Inner.info())中的'info()'方法,所以应该返回'info()'方法的结果之前初始化'Inner'类。 That's why this is the step 4. 这就是为什么这是第4步。

5 - Finally, the System.out has all data it needs to show, and then the last line is showed on the console. 5 - 最后,System.out包含它需要显示的所有数据,然后在控制台上显示最后一行。

So, as it was well pointed by @sotirios-delimanolis ( Does the Java ClassLoader load inner classes? ) loading a class is different from initializing it. 因此,@ sotirios-delimanolis( Java ClassLoader是否加载内部类? )加载一个类与初始化它有所不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM