java9jdk⽂档_Java9揭秘(8.JDK9重⼤改变下)
Tips
做⼀个终⾝学习的⼈。
Java 9
六. 资源命名语法
资源使⽤由斜线分隔的字符串序列命名,例如com/jdojo/states.png,/com/jdojo/words.png和logo.png。 如果资源名称以斜线开头,则被视为绝对资源名称。
使⽤以下规则从资源名称中估算包(package)的名称:
如果资源名称以斜线开头,删除第⼀个斜线。 例如,对于资源名称/com/jdojo/words.png,此步骤将导致com/jdojo/words.png。
从最后⼀个斜线开始删除资源名称中的所有字符。 在这个例⼦中,com/jdojo/words.png导致com/jdojo。
⽤点号(.)替换名称中的每个剩余的斜线。 所以,com/jdojo被转换成com.jdojo。 ⽣成的字符串是包名称。
有些情况下使⽤这些步骤会导致⼀个未命名的包或⼀个⽆效的包名称。 包名称(如果存在)必须由有效的Java标识符组成。 如果没有包名称,它被称为未命名的包。 例如,将META-INF/resource /logo.png视为资源名称。 应⽤上⼀组规则,其包名称将被计算为“sources”,它不是有效的包名,但它是资源的有效路径。
七. 查资源的规则
由于向后兼容性和对模块系统的强封装的承诺,JDK 9中查资源的新规则是复杂的,基于以下⼏个因素:
包含资源的模块类型:命名的,开放的,未命名的或⾃动命名的模块;
正在访问资源的模块:它是同⼀个模块还是另⼀个模块?
正在被访问的资源的包名称:它是否是有效Java包? 这是⼀个未命名的包?
封装包含资源的包:将包含资源的包导出,打开或封装到访问资源的模块?
正在访问的资源的⽂件扩展名:资源是.class⽂件还是其他类型的⽂件?
正在使⽤哪种类的⽅法来访问资源:Class,ClassLoader或Module类?
以下规则适⽤于包含资源的命名模块:
如果资源名称以.class结尾,则可以通过任何模块中的代码访问资源。 也就是说,任何模块都可以访问任何命名模块中的类⽂件。
如果从资源名称计算的包名称不是有效的Java包名称,例如sources,则可以通过任何模块中的代码访问该资源。
如果从资源名称计算的包名称是未命名的包,例如对于资源名称(如word.png),则可以通过任何模块中的代码访问该资源。
如果包含该资源的软件包对访问该资源的模块开放,则资源可以通过该模块中的代码访问。 ⼀个包对模块开放,因为定义包的模块是⼀个开放的模块,或者模块打开所有其他模块的包,或者模块只使⽤⼀个限定的打开语句打开包。 如果没有以任何这些⽅式打开包,则该包中的资源不能被该模块外的代码访问。
这个规则是上⼀个规则的分⽀。 打开未命名,⾃动或开放模块中的每个包,因此所有其他模块中的代码都可以访问这些模块中的所有资源。
Tips
命名模块中的包必须打开,⽽不是导出,以访问其资源。 导出⼀个模块的包允许其他模块访问该包中的公共类型(⽽不是资源)。
在访问命名模块中的资源时,Module,Class和ClassLoader类中的各种资源查⽅法的⾏为有所不同:
可以使⽤Module类的getResourceAsStream()⽅法来访问模块中的资源。 此⽅法是调⽤⽅敏感的。 如果调⽤者模块不同,则此⽅法将应⽤所有资源可访问性规则,如上所述。
在指定模块中定义的类的Class类中的getResource *()⽅法仅在该命名模块中定位资源。 也就是说,不能使⽤这些⽅法来定位定义调⽤这些⽅法的类的命名模块之外的类。
ClassLoader类中的getResource *()⽅法基于前⾯描述的规则列表来定位命名模块中的资源。 这些⽅法不是调⽤者敏感的。 在尝试查资源本⾝之前,类加载器将资源搜索委托给其⽗类。 这些⽅法有两个例外:1)它们仅在⽆条件打开的包中定位资源。 如果使⽤限定的打开语句打开包,则这些⽅法将不
会在这些包中到资源。 2)它们搜索在类加载器中定义的模块。
Class对象将仅在它所属的模块中到资源。 它还⽀持以斜线开头的绝对资源名称,以及不以斜线开头的相对资源名称。 以下是使⽤Class 对象的⼏个⽰例:
// Will find the resource
URL url1 = Resource("Test.class");
// Will not find the resource because the Test and Object classes are in different modules
URL url2 = Resource("/java/lang/Object.class");
// Will find the resource because the Object and Class classes are in the same module, java.base
URL url3 = Resource("/java/lang/Class.class");
// Will not find the resource because the Object class is in the java.base module whereas
java学习资源// the Driver class is in the java.sql module
URL url4 = Resource("/java/sql/Driver.class");
使⽤Module类定位资源需要具有该模块的引⽤。 如果可以访问该模块中的类,则在该Class对象上使⽤getModule()⽅法给出了模块引⽤。 这是获取模块引⽤的最简单⽅法。 有时候,你把模块名称作为字符串,⽽不是该模块中的类的引⽤。 可以从模块名称中到模块引⽤。 模块被组织成由java.lang包中的ModuleLayer类的实例表⽰的层。 JVM⾄少包含⼀个boot 层。 boot层中的模块映射到内置的类加载器 —— 引导类加载器,平台类加载器和应⽤程序类加载器。 可以使⽤ModuleLayer类的boot()静态⽅法获取boot层的引⽤:
// Get the boot layer
ModuleLayer bootLayer = ModuleLayer.boot();
⼀旦获得boot层的引⽤,可以使⽤其findModule(String moduleName)⽅法获取模块的引⽤:
// Find the module named source in the boot layer
Optional m = bootLayer.findModule("source");
// If the module was found, find a resource in the module
if(m.isPresent()) {
Module testModule = m.get();
String resource = "com/jdojo/resource/opened/opened.properties";
InputStream input = ResourceAsStream(resource);
if (input != null) {
System.out.println(resource + " found.");
} else {
System.out.println(resource + " not found.”);
}
} else {
System.out.println("Module source does not exist");
}
⼋. 访问命名模块中的资源的⽰例
在本部分中,将看到资源查规则的具体过程。 在source的模块中打包资源,其声明如下所⽰。
// module-info.java
module source {
exports ported;
opens com.jdojo.opened;
}
该模块导出ported包,并打开com.jdojo.opened包。
以下是source模块中所有⽂件的列表:
module-info.class
unnamed.properties
META-INF\invalid_pkg.properties
com\jdojo\encapsulated\encapsulated.properties
com\jdojo\encapsulated\EncapsulatedTest.class
com\jdojo\exported\AppResource.class
com\jdojo\exported\exported.properties
com\jdojo\opened\opened.properties
com\jdojo\opened\OpenedTest.class
有四个类⽂件。 在这个例⼦中,只有module-info.class⽂件很重要。 其他类⽂件定义⼀个没有任何细节的同名的类。 具有.properties扩展名的所有⽂件都是资源⽂件,其内容在此⽰例中不重要。 源代码包含Java9Revealed\source⽬录中这些⽂件的内容。
unnamed.properties⽂件在未命名的包中,因此可以通过任何其他模块中的代码来定位。 invalid_pkg.properties⽂件位于META-INF⽬录中,它不是有效的Java包名称,因此该⽂件也可以通过
任何其他模块中的代码来定位。 apsulated包没有打开,所以encapsulated.properties⽂件不能通过其他模块中的代码来到。 ported包未打开,所以export.properties⽂件不能通过其他模块中的代码来到。 com.jdojo.opened包是打开的,所以opened.properties⽂件可以通过其他模块中的代码来定位。该模块中的所有类⽂件可以通过其他模块中的代码来定位。
下⾯清单包含st模块的模块声明。本模块中的代码将尝试访问source模块中的资源以及本模块中的资源。你需要将source模块添加到此模块路径以进⾏编译。 在 NetBean IDE中st项⽬的属性对话框如下图所⽰。它将source模块添加到其模块路径。
Adding module to the module path
// module-info.java
module st {
requires source;
exports st;
}
st模块中的⽂件按如下⽅式排列:
module-info.class
com\jdojo\resource\test\own.properties
com\jdojo\resource\test\ResourceTest.class
该模块包含名为own.properties的资源⽂件,该⽂件位于st包中。 own.properties⽂件为空。 下⾯包含ResourceTest类的代码。
// ResourceTest
package st;
import ported.AppResource;
import java.io.IOException;
import java.io.InputStream;
public class ResourceTest {
public static void main(String[] args) {
// A list of resources
String[] resources = {
"java/lang/Object.class",
"com/jdojo/resource/test/own.properties",
"com/jdojo/resource/test/ResourceTest.class",
"unnamed.properties",
"META-INF/invalid_pkg.properties",
"com/jdojo/opened/opened.properties",
"com/jdojo/exported/AppResource.class",
"com/jdojo/resource/exported.properties",
"com/jdojo/encapsulated/EncapsulatedTest.class",
"com/jdojo/encapsulated/encapsulated.properties"
};
System.out.println("Using a Module:");
Module otherModule = Module();
for (String resource : resources) {
lookupResource(otherModule, resource);
}
System.out.println("\nUsing a Class:");
Class cls = ResourceTest.class;
for (String resource : resources) {
// Prepend a / to all resource names to make them absolute names
lookupResource(cls, "/" + resource);
}
System.out.println("\nUsing the System ClassLoader:"); ClassLoader clSystem = SystemClassLoader();
for (String resource : resources) {
lookupResource(clSystem, resource);
}
System.out.println("\nUsing the Platform ClassLoader:"); ClassLoader clPlatform = PlatformClassLoader(); for (String resource : resources) {
lookupResource(clPlatform, resource);
}
}
public static void lookupResource(Module m, String resource) {
try {
InputStream in = m.getResourceAsStream(resource);
print(resource, in);
} catch (IOException e) {
System.out.Message());
}
}
public static void lookupResource(Class cls, String resource) { InputStream in = ResourceAsStream(resource);
print(resource, in);
}
public static void lookupResource(ClassLoader cl, String resource) { InputStream in = cl.getResourceAsStream(resource);
print(resource, in);
}
private static void print(String resource, InputStream in) {
if (in != null) {
System.out.println("Found: " + resource);
} else {
System.out.println("Not Found: " + resource);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论