Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.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 字段和代码中的可选类型,是否安全?_Java_Jvm_Classloader - Fatal编程技术网

Java 字段和代码中的可选类型,是否安全?

Java 字段和代码中的可选类型,是否安全?,java,jvm,classloader,Java,Jvm,Classloader,我有一门课是这样的: class Environment { somelib.SomeType someOptionalDep = null; public void doSomething() { boolean found = false; try { Class.forName("somelib.SomeType"); found = true; } catch (Class

我有一门课是这样的:

class Environment {

    somelib.SomeType someOptionalDep = null;

    public void doSomething() {
        boolean found = false;
        try {
            Class.forName("somelib.SomeType");
            found = true;
        } catch (ClassNotFoundException e) {
        }
        if (found) {
            someOptionalDep = new somelib.SomeType();
            // ...
        }
    }

}
somelib
是一个可选包:存在于编译时,但从基本jar中排除。事实上,这段代码没有依赖关系(Debian 8上的Oracle Java HotSpot 1.8.0111),但这真的安全吗

注意:我知道,我可以将可选功能包装在单独的类中,但在某些情况下,这太复杂了

编辑:

从Oracle的
NoClassDefFoundError
文档中:

如果Java虚拟机或
ClassLoader
实例尝试加载类的定义(作为普通方法调用的一部分,或作为使用
new
表达式创建新实例的一部分),并且找不到类的定义,则引发

编译当前执行的类时,已存在搜索的类定义,但无法再找到该定义


遗憾的是,它没有明确说明声明或已加载但未执行的代码。

不,这不起作用。加载类时,VM还会查找
SomeType
,并抛出错误。正确的方法是创建一个也包含在base.jar中的接口,让SomeType实现该接口,然后执行以下操作:

class Environment {
  SomeInterface someOptionalDep = null;
    public void doSomething() {
      try {
        Class c = Class.forName("somelib.SomeType");        
        someOptionalDep = c.newInstance();
      } catch (ClassNotFoundException, InstantiationException, IllegalAccessException e) {
      }
    }
}

我相信你的主要问题已经在评论中陈述了


对于可能不存在的类型,字段声明是否安全

“安全”的意思似乎是“不会导致
NoClassDefFoundError


在回答这个问题之前,我想说你最好不要那样做。在您的代码中有一个不存在的类型会使它变得不必要的复杂-这是不安全的。可选的依赖关系最好由一种网关来处理,该网关将业务逻辑与依赖关系分开。Roberto Attias建议的附加接口就是一个例子。您还可以将自己的接口引入到实现中:一个将所有调用委托给可选的依赖项,另一个什么也不做


从技术上讲,答案是肯定的

JVM倾向于尽可能懒惰地做事情——尤其是类加载。加载类时,JVM将只加载其超类和超接口,而不加载代码中使用的其他类型

此外,即使读取和写入不存在类型的字段本身也不会引发类加载(以及
NoClassDefFoundError
)。这是可能的,因为

  • 如果您正在读取一个字段,那么类加载可以推迟,直到您实际使用它
  • 如果您正在编写一个非null值,那么您已经加载了创建实例的类型
  • 如果将null写入字段,则类型无关紧要(因为null可以分配给任何值)

顺便说一句,方法的参数和返回值也是如此。

这有什么意义?为什么不捕获
NoClassDefFoundError
?字段声明对可能不存在的类型是否安全?我怀疑它能工作,除非环境类没有首先加载。@Roberto Attias:正如@shmosel所说,我在Debian 8上用Oracle Java HotSpot 1.8.0111尝试过这一点,并且成功了。“
someOptionalDep
”存储第三方库类的实例,该类通常没有可移植接口(可能是
对象someOptionalDep
)。请更正。事实上,这应该保证任何遵守规范的JVM都会这样做:在工作时多考虑一下这一点,它会使代码变得非常脆弱。您能否提供一个关于您使用的库中有多少函数的估计,以及当这些函数不可用时您会做什么?JLS的参考是什么?该链接指向“类和接口的初始化”,与问题无关。“可选依赖项最好由一种将业务逻辑与依赖项分离的网关来处理。”-一般来说,这一点很好,但在我看来,这种特殊情况属于例外情况。我的包是对一些依赖于平台的资源的轻量级抽象,其中无法实现繁忙逻辑。@DávidHorváth从这一点和你的其他评论来看,
环境
似乎已经使用了类似于我试图描述的内容,即它安全地封装了对
某种类型
的访问,将其提供给业务逻辑,不做更多的事情。如果是的话,没关系。否则,这也没关系:)因为这是你深思熟虑的选择,你是唯一能够做出决定的人。