Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用java.lang.class实例初始化(加载)java类_Java_Class_Reflection_Initialization - Fatal编程技术网

使用java.lang.class实例初始化(加载)java类

使用java.lang.class实例初始化(加载)java类,java,class,reflection,initialization,Java,Class,Reflection,Initialization,我不得不承认,这更像是一个表面问题,但事实上,我还没有找到一个更直接的解决方案,这让我觉得我可能遗漏了一些东西 问题是,我的类假设Foo有一个非常重要的静态块,它在映射中用一个builder方法注册Foo.class,如下所示: // somewhere in the class static { Bar.registerBuilder(Foo.class, Foo::build); } // somewhere in a method Foo foo = Bar.getBuilder

我不得不承认,这更像是一个表面问题,但事实上,我还没有找到一个更直接的解决方案,这让我觉得我可能遗漏了一些东西

问题是,我的类假设Foo有一个非常重要的静态块,它在映射中用一个builder方法注册Foo.class,如下所示:

// somewhere in the class
static {
    Bar.registerBuilder(Foo.class, Foo::build);
}
// somewhere in a method
Foo foo = Bar.getBuilder(Foo.class).apply("Hello World");
这使得可以从Bar类中获取Foo生成器,有点像这样:

// somewhere in the class
static {
    Bar.registerBuilder(Foo.class, Foo::build);
}
// somewhere in a method
Foo foo = Bar.getBuilder(Foo.class).apply("Hello World");
如果生成器接受字符串参数。但是,上面的代码示例仅在Foo类已经初始化时才起作用。如果没有,这意味着Foo的静态块没有被执行,而且构建器现在还没有在Bar中注册,这导致getBuilder返回null,apply抛出NullPointerException

多亏了互联网,我发现你可以强制使用Class.forNameString。但真正让我困惑的是,这个方法接受一个字符串,因此抛出选中的ClassNotFoundException,而我还没有找到通过java.lang.class实例直接加载和初始化类的方法。我本以为会是这样的

Class<Foo> clazz = Foo.class;
clazz.load(); // does not exist
相反,我必须这样做:

Class<Foo> clazz = Foo.class;
try {
    Class.forName(clazz.getName());
} catch (ClassNotFoundException) {
    // handle an exception that is actually unreachable
}
我想知道我是否完全遗漏了什么,或者如果没有,是否有更干净的方法通过java.lang.class表示加载和初始化类

非常感谢您的帮助,谢谢

编辑1:正如蜘蛛@Boris在评论中指出的那样,Foo.class可能已经加载并初始化了该类,但至少在我的情况下没有,这就是为什么我甚至遇到了这个问题

编辑2:如代码示例中所示,使用复杂的方式通过class.forName加载类实际上解决了我所想的问题。只是如果可能的话,我想用一种更干净的方式

使用:

Java11OpenJDK11.0.2 IntelliJ IDEA终极版2019.3 Maven 3.6.3
如果您已经在引用该类,那么最好将该静态代码移动到普通的静态工厂方法中。既然可以运行某个类,为什么还要使用反射或引用某个类来运行某个代码呢

public static BuilderFunction createBuilder() {
    return Foo::build;
}
只需在条的静态块中调用它:

如果您需要更具动态性的内容,可以使用服务加载器,尤其是java 9+,因为它们现在更易于使用:

provides my.BuilderProvder with something.FooProvider;
然后把它们都装到酒吧里:

ServiceLoader<BuilderProvder> loader = ServiceLoader.load(BuilderProvder.class);
loader.stream()
      .forEach(provider -> registerBuilder(provider));
现在,即使不是由您开发的不同模块也可以提供自己的构建器,并且您不需要进行任何手动类加载,并且只有在实际使用类时才能保证类初始化,就像使用了某些方法或字段一样——请注意,常量在编译时是内联的,所以它们不计算在内


您还可以使用一些粗糙的反射库(如ClassGraph或Reflections)来获取具有给定注释的给定类型/的所有类,然后加载它们并对它们调用一些init方法,就像我第一次使用createBuilder提出的解决方案一样。这就是spring中注册了多少组件,类似的事情可以通过java注释预处理在编译时找到这些类并保存名称。但如果可能的话,我建议坚持使用现有的内置解决方案,如服务加载程序。

@Boris the Spider实际上,这正是我第一次想到为什么没有java.lang.Class.load。但问题是,我最初遇到这个问题是因为我试图从Bar中获取生成器,但我得到了上面提到的NullPointerException。显然,Foo.class不会在Java11OpenJDK11.0.2中加载或初始化Foo。我也很困惑,但这基本上是我问题的根源。处理这个场景。@BoristheSpider初始化与加载完全不同,因此只能在加载后进行,因为它需要加载的类。虽然故意不指定类加载的时间,但初始化的时间是。不,使用文本Foo.class不在这个列表中。