如果我有一个内部类声明,例如:
Class A {
public static class B {
}
}
其次是:
Class<?> implClass = getClass().getClassLoader().loadClass("A");
A$B内部类也会加载吗?如果B内部类没有被声明为“静态”呢?
一个ClassLoader
将不会加载一个类,除非它被请求(例如使用loadClass
)。加载类时,ClassLoader
将请求引用的类。
由于您的类A
没有引用A.B
,A.B
将不会被加载,无论它是否是静态的。(老实说,A
确实引用了A.B
,但不会导致ClassLoader
加载A.B
)
如果您添加类型为a.B
的字段,或以另一种方式使用类型a.B
(例如,作为方法返回类型),它实际上将在a.class
中引用,因此将被加载。
内部类,即类B
不能存在于父类之外。您需要首先构造父类,即class 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 });
一旦代码被编译,就没有所谓的内部类了。如果您查看javac
的结果,您将看到两个文件:
A.class
A$B.class
因此,当加载A
时,类B
不会加载,B
恰好是在A
中定义的。
例如,给定这两个文件,
package kuporific;
public class A {
private static class B {}
private class C {}
}
和一个build.gradle
文件(为了方便):
apply plugin: 'java'
首先,通过运行gradlebuild
进行构建。然后,解压缩生成的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
对A$B
和A$C
有什么影响。
首先,添加以下Java类:
package kuporific;
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Main.class.getClassLoader().loadClass("kuporific.A");
}
}
现在将以下内容添加到构建中。渐变
文件:
apply plugin: 'application'
mainClassName = 'kuporific.Main'
applicationDefaultJvmArgs = ["-verbose:class"]
-verbose:class
输出JVM加载的所有类(请参阅Java-获取JVM中加载的所有类的列表)。
在命令行上运行gradlerun
(运行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
我们可以看到当kuporify。主代码和代码。加载了一个
,我们没有看到两个kuporify。A$B
或kuporify。正在加载$C
。
问题内容: 如果我有一个内部类声明,例如: 其次是: A $ B内部类也将被加载吗?如果B内部类未声明为“静态”怎么办? 问题答案: 一旦代码被编译, 就没有内部类之类的东西 。如果查看的结果,则会看到两个文件: 因此,类在加载时不会加载,只是 碰巧 在中定义了。 编辑 例如,鉴于这两个文件, 和一个文件(为方便起见): 首先,通过运行进行构建。然后,解压缩生成的JAR文件(位于中): 打开每个文
CLMAIN->clA(类A,$B)。$B是类a的内部类B。 从clMain创建具有指定url的新clA到包含类A(和类$B)的jar文件。然后通过CLA创建新对象A。 从X加载的另一个类通过接口执行对象a的方法没有问题。 然后,在该方法中,应该创建新对象$b,但它抛出. 在类A的构造函数中加载类$B可以解决以下问题:
问题内容: 我们知道我们可以使用以下方法覆盖System 类加载器: 那么,既然它本身是一个类,它是由谁加载的? 我们如何获得该“元”类加载器的类文件? 问题答案: 从Javadoc中获取: 如果在首次调用此方法时定义了系统属性“ java.system.class.loader”,则该属性的值将作为要作为系统类加载器返回的类的名称。 该类使用默认的系统类加载器加载, 并且必须定义一个公共构造函数
因此,我有一个类加载器加载一个类,如下所示: 类在运行时位于另一个jar中。以及是在主jar中生成的,然后我取消了它的归档,所以依赖项就在那里。 如何从外部访问其他依赖项。我加载的类文件? 例外情况:
框架中所有的类都是通过类加载器(ClassLoader)加载的,通过Loader我们可以实现类的统一管理。下面我们一起来看看Loader提供了哪些加载方法: 1. Loader::import 加载一个类或者加载一个包 方法原型 import( $classPath, $type = IMPORT_APP, $extension=EXT_PHP ) 参数名称 参数说明 $classPath 文件的
加载器,顾名思义,是用于加载元素的,加载的元素可以是库(类),视图文件 , 驱动器 ,辅助函数 , 模型 或其他你自己的文件。 注解 该类由系统自动加载,你无需手工加载。 应用程序"包" 包的视图文件 类参考 应用程序"包" 应用程序包(Package)可以很便捷的将你的应用部署在一个独立的目录中, 以实现自己整套的类库,模型,辅助函数,配置,文件和语言包。 建议将这些应用程序包放置在 appli