序文
java
私が最初に連絡した とき、物事のFile
相対パス、つまり参照として使用するディレクトリについて混乱してい ました。
IOモデルの発展に伴い、Javaの1.7の nio
使用 Path
、Paths
及び Files
その上には、IO操作を容易にします。
ClassLoader
class 文件
ioの 取得に使用しましたが、ファイルioの取得にも使用できるため、ファイルの内容を読み取ることができます。
この記事のデザインコンテンツ
- File、ZipFile、JarFileは、相対パスと絶対パスファイルの内容を読み取ります。
- System.getProperty( "user.dir")の由来は?
- パス、パス、ファイルはファイルの内容を読み取ります。
- クラスローダーは、ファイルコンテンツClass.getResourceAsStreamおよびClassLoader.getResourceAsStreamを取得します。
- クラスローダーの親の委譲モデルを紹介し、コードで対応する読み込みロジックを見つけます。
<font color = red>コードはMac 10.15.4
JDK 1.8に基づいてい ます。</フォント>
ファイルに基づいてファイルのコンテンツを取得する
絶対パスのコンテンツの取得は比較的簡単で、ファイルioを直接取得し、ツールクラスを使用してファイルのコンテンツを読み取ります。
絶対パスファイルの内容を取得する
final File file = new File("/Users/zhangpanqin/github/fly-java/demo.txt");
final byte[] bytes = cn.hutool.core.io.FileUtil.readBytes(file); System.out.println(new String(bytes, StandardCharsets.UTF_8));
JarFileのコンテンツを取得する
JarFile
継承は ZipFile
、jarパッケージのコンテンツを取得するために使用されます。たとえば、jar内のファイルの内容を取得したいとします。
final File file = new File("/Users/zhangpanqin/github/fly-java/src/main/resources/fastjson-1.2.68.jar");
final JarFile jarFile = new JarFile(file); final JarEntry jarEntry = jarFile.getJarEntry("META-INF/LICENSE.txt"); final InputStream inputStream = jarFile.getInputStream(jarEntry); // 工具类是 hutool System.out.println(IoUtil.read(inputStream, StandardCharsets.UTF_8)); IoUtil.close(inputStream);
相対パスのコンテンツを取得する
File.getAbsolutePath
ソースコードを見ると、相対パスが実際に前にステッチされていることがわかります System.getProperty("user.dir")
。
class UnixFileSystem extends FileSystem { public String resolve(File f) { if (isAbsolute(f)) return f.getPath(); return resolve(System.getProperty("user.dir"), f.getPath()); } }
私たちがそれを理解する限り System.getProperty("user.dir")
、問題は解決されます。Javaのシステムプロパティは で説明し user.dir
、ユーザーの作業ディレクトリ。
<font color = red>ユーザーの作業ディレクトリは何ですか?これは、javaコマンドが実行されるディレクトリです。</ font>そのディレクトリでコマンドを実行すると、usr.dirがjava仮想マシンによってコマンドを実行するためのパスとして割り当てられます。/Users/zhangpanqin/github/fly-java/test
コンパイルしたclass
ファイルをディレクトリで 実行し ます。-cp
クラスパスパスを指定します。
nio読み取りファイルの内容
Path
類推して使用できます File
。そして、ツールが Paths
利用できる Path
、Files
だけでなく、ファイルを操作するためのCRUDのAPIを豊富に提供して Path
。
絶対パスのコンテンツを取得する
@Test
public void run33() throws IOException { final Path path = Paths.get("/Users/zhangpanqin/github/fly-java/demo.txt"); final byte[] bytes = Files.readAllBytes(path); System.out.println(new String(bytes,StandardCharsets.UTF_8)); }
相対パスのコンテンツを取得する
Paths
相対パスを取得するときに、パスが/
開始されません 。また、System.getProperty("user.dir")
パスに対する相対としても理解でき ます。
public static void main(String[] args) { System.out.println(System.getProperty("user.dir")); System.out.println(Paths.get("").toAbsolutePath()); }
ClassLoaderに基づいてファイルコンテンツを取得する
ClassLoader.getResourceAsStream
// ClassLoader.getResourceAsStream java 1.8 源码
public InputStream getResourceAsStream(String name) { URL url = getResource(name); try { return url != null ? url.openStream() : null; } catch (IOException e) { return null; } }
コードから、メインロジックがまだ集中していることがわかり getResource
ます。
public URL getResource(String name) {
URL url;
if (parent != null) { url = parent.getResource(name); } else { url = getBootstrapResource(name); } if (url == null) { url = findResource(name); } return url; }
上記のコードのロジックは、よく耳にするもの 双亲委派机制
です。してみましょう 父类加载
リソースをロードするために、そして自分が探してそこに見つけることができません。类加载器单独讲
。
クラスローダーはリソースを読み取って読み取り、最初にそれが担当するパスから検索します。たとえば、アプリケーションクラスローダーは リソースの検索をsun.misc.Launcher.AppClassLoader#AppClassLoader
担当し classpath
ます。リソースを読み取るクラスローダーの 利点File
と Path
欠点は何 ですか?たとえばjar
、リソースの1つを取得したい 場合、パスを使用するのはより面倒ですClassLoaderは、責任のあるパスから見つけることも、jarパッケージに見つけることもできます。
final URL resource = Test2.class.getClassLoader().getResource("com/alibaba/fastjson/JSONArray.class"); System.out.println(resource);
上記の印刷結果
jar:file:/Users/zhangpanqin/.m2/repository/com/alibaba/fastjson/1.2.62/fastjson-1.2.62.jar!/com/alibaba/fastjson/JSONArray.class
パスも取得できます inputstream
@Test
public void run222(){ final InputStream resourceAsStream = Test2.class.getClassLoader().getResourceAsStream("META-INF/maven/com.alibaba/fastjson/pom.properties"); System.out.println(IoUtil.read(resourceAsStream, StandardCharsets.UTF_8)); }
上記の結果は次のとおりです。
#Generated by Maven
#Mon Oct 07 22:09:36 CST 2019
version=1.2.62
groupId=com.alibaba
artifactId=fastjson
Class.getResourceAsStream
Class.getResourceAsStream
ClassLoader
ロードリソースは 実際にはと呼ばれ ますが、現在のクラスが配置されているパッケージからの相対パスにパスが追加されます。
たとえば
// com.fly.study.java.classloader.Test2
@Test
public void run555(){ System.out.println(Test2.class.getResource("name")); }
見つかった実際のリソースは com.fly.study.java.classloader.name
です。現在のクラスが配置されているパッケージのリソースを基準にします。
クラスローダー
クラスローダーについてよく耳にします 双亲委派模型
。
これらのクラスが読み込まれた場所はどこにありますか?
启动类加载器
ソースコードがJavaコードに実装されていない場合、ソースコードは表示されません。
sun.misc.Launcherクラスは、私たちが知っている 扩展类加载器 sun.misc.Launcher.ExtClassLoader
と 应用类加载器 sun.misc.Launcher.AppClassLoader
。
java.lang.ClassLoader#getSystemClassLoader
コードを見ると、実際のアプリケーションクラスローダーが返されます。
public static ClassLoader getSystemClassLoader() { initSystemClassLoader(); if (scl == null) { return null; } SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkClassLoaderPermission(scl, Reflection.getCallerClass()); } return scl; } private static synchronized void initSystemClassLoader() { if (!sclSet) { sun.misc.Launcher l = sun.misc.Launcher.getLauncher(); if (l != null) { Throwable oops = null; scl = l.getClassLoader(); } } }
コードテストを実行すると、アプリケーションクラスローダーが返されます。
// sun.misc.Launcher$AppClassLoader@18b4aac2
@Test
public void run66(){
System.out.println(ClassLoader.getSystemClassLoader());
}
これらの3つのクラスローダーは、異なるパスでクラスをロードする責任があります。
ブートクラスローダーの紹介
启动类加载器 BootClassLoader
System.getProperty("sun.boot.class.path")
クラスのロードを 担当します。それは次のカテゴリーです。
${JAVA_HOME}/jre/lib/*.jar
そして ${JAVA_HOME}/jre/classes
クラスローディング。
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/resources.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/rt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/sunrsasign.jar /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jsse.jar /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jce.jar /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/charsets.jar /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/jfr.jar /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/classes
@Test
public void run77() { final URLClassPath bootstrapClassPath = Launcher.getBootstrapClassPath(); final URL[] urLs = bootstrapClassPath.getURLs(); Stream.of(urLs).forEach(item->{ System.out.println(item.getFile()); }); }
拡張クラスローダー
扩展类加载器 sun.misc.Launcher.ExtClassLoader
読み込み System.getProperty("java.ext.dirs")
クラスです。
@Test
public void run99() { final String property = System.getProperty("java.ext.dirs"); final String[] split = property.split(":"); Stream.of(split).forEach(item -> { System.out.println(item); }); }
/Users/zhangpanqin/Library/Java/Extensions
/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre/lib/ext
/Library/Java/Extensions
/Network/Library/Java/Extensions
/System/Library/Java/Extensions
/usr/lib/java
アプリケーションクラスローダー
应用类加载器 sun.misc.Launcher.AppClassLoader
読み込み中 System.getProperty("java.class.path");
# -cp 指定 classpath 路径,多个路径可以使用 : 分开(linux 下为 :,window 下为 ;),
java -cp /Users/zhangpanqin/github/fly-java/target/classes com.fly.study.java.classloader.Test2