bea*_*ear 6 java interface java-9
假设你有moduleA和moduleB.ModuleA定义了一个接口(例如用于服务),ModuleB有一个实现接口的具体类(提供服务).
现在,如果接口有一个默认方法,并且你在moduleB中的类(来自另一个模块)上调用它,那么这个调用应该在moduleA或moduleB中执行吗?显然它来自moduleA ......理由是什么?
示例:假设您有一个执行此操作的代码:
InputStream is = this.getClass().getResourceAsStream(fullPath);
Run Code Online (Sandbox Code Playgroud)
如果此代码位于moduleB中服务的实现中,则将打开流.但是如果代码位于moduleA中的默认方法中,那么当在moduleB上调用服务时,您需要在moduleB中拥有一个"open"资源(因此看起来调用认为它来自"outside"moduleB).
我想了解一下原因.
谢谢
用一个例子编辑我的问题.假设你在moduleA中有这段代码:
public interface PropertiesProvider {
public default Properties get(String domain) {
Class clazz =this.getClass();
System.out.println(" CLASS " +clazz);
InputStream is = clazz.getResourceAsStream(domain) ;
if (is != null) {
Properties props = new Properties();
try {
props.load(is);
return props;
} catch (IOException e) {
//log
}
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
}
在moduleB中
public class PropertiesProviderImpl implements PropertiesProvider {}
Run Code Online (Sandbox Code Playgroud)
如果您从ModuleA调用该服务,则调用该调用来自类PropertiesProviderImpl查找资源但如果它未被"打开"则不加载它
如果将代码复制到PropertiesProviderImpl中,则调用会追溯到同一个类找到ressource并加载它,即使它没有"打开"
所以我的问题是:为什么调用后的差异来自同一个类?(不同之处在于,在一种情况下,该方法是从接口中的默认方法继承的类型)
查看getResourceAsStream的文档 If this class is in a named Module then this method will attempt to find the resource in the module.
在第一种情况下,您的代码(在moduleA)中可以看到 ,Type但看不到实现您的 的类Type,因为它位于moduleB. 在第二种情况下,您的代码可以看到“实现” Type.
看看下面的参考资料,最重要的句子是:
\n\n\n\n\n在模块化设置中,只要上下文类加载器知道包含提供程序类的包,Class::forName 的调用就会继续工作。但是,通过反射 newInstance 方法调用提供程序 class\xe2\x80\x99s 构造函数将不起作用:提供程序可能会从类路径加载,在这种情况下,它将位于未命名模块中,或者可能是在某些命名模块中,但无论哪种情况,框架本身都位于 java.xml 模块中。该模块仅依赖于基本模块,因此读取基本模块,因此框架将无法访问任何其他模块中的提供程序类。
\n
[...]
\n\n\n\n\n相反,只需修改反射 API,假设反射某种类型的任何代码都位于可以读取定义该类型的模块的模块中。
\n
[长答案]:反射可读性
\n\n\n\n\n框架是一种在运行时使用反射来加载、检查和实例化其他类的工具[...]
\n\n给定在运行时发现的类,框架必须能够访问其构造函数之一才能实例化它。然而,就目前情况而言,情况通常并非如此。
\n\n例如,platform\xe2\x80\x99s 流式 XML 解析器加载并实例化由系统属性 javax.xml.stream.XMLInputFactory 命名的 XMLInputFactory 服务的实现(如果已定义),优先于通过 ServiceLoader 类发现的任何提供程序。忽略异常处理和安全检查,代码大致如下:
\n
String providerName\n = System.getProperty("javax.xml.stream.XMLInputFactory");\nif (providerName != null) {\n Class providerClass = Class.forName(providerName, false,\n Thread.getContextClassLoader());\n Object ob = providerClass.newInstance();\n return (XMLInputFactory)ob;\n}\n// Otherwise use ServiceLoader\n...\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n在模块化设置中,只要上下文类加载器知道包含提供程序类的包,Class::forName 的调用就会继续工作。但是,通过反射 newInstance 方法调用提供程序 class\xe2\x80\x99s 构造函数将不起作用:提供程序可能是从类路径加载的,在这种情况下,它将位于未命名模块中,或者可能是在某些命名模块中,但无论哪种情况,框架本身都位于 java.xml 模块中。该模块仅依赖于基本模块,因此读取基本模块,因此框架将无法访问任何其他模块中的提供程序类。
\n\n为了使框架可以访问提供程序类,我们需要使框架\xe2\x80\x99s 模块可以读取提供程序\xe2\x80\x99s 模块。我们可以要求每个框架在运行时显式地将必要的可读性边缘添加到模块图中,如本文档的早期版本所示,但经验表明这种方法很麻烦并且会阻碍迁移。
\n\n因此,我们只是修改反射 API,假设反射某种类型的任何代码都位于可以读取定义该类型的模块的模块中。这使得上面的示例和其他类似代码无需更改即可工作。这种方法不会削弱强封装性:公共类型必须仍然位于导出的包中,以便从其定义模块外部访问,无论是通过编译代码还是通过反射。
\n