本文共 5830 字,大约阅读时间需要 19 分钟。
本章节将介绍Java虚拟机如何从指定路径寻找并读取Java类文件的字节码。
为了完成本例案例,建议使用以下环境:
项目文件结构如下:
itstack-demo-jvm-02├── pom.xml└── src ├── main │ └── java │ └── org.itstack.demo.jvm │ ├── classpath │ │ ├── impl │ │ │ ├── CompositeEntry.java │ │ │ ├── DirEntry.java │ │ │ ├── WildcardEntry.java │ │ │ └── ZipEntry.java │ │ ├── Classpath.java │ │ └── Entry.java │ ├── Cmd.java │ └── Main.java └── test └── java └── org.itstack.demo.test └── HelloWorld.java
package org.itstack.demo.test;import org.itstack.demo.jvm.classpath.Classpath;import java.util.Arrays;public class HelloWorld { public static void main(String[] args) { // 请根据实际需要添加相应的参数 Cmd cmd = Cmd.parse(args); // 进行JVM启动和类加载等操作 }} package org.itstack.demo.jvm.classpath;import org.itstack.demo.jvm.classpath.impl.WildcardEntry;import java.io.File;import java.nio.file.Files;import java.nio.file.Paths;public class Classpath { private Entry bootstrapClasspath; private Entry extensionClasspath; private Entry userClasspath; public Classpath(String jreOption, String cpOption) { bootstrapAndExtensionClasspath(jreOption); parseUserClasspath(cpOption); } private void bootstrapAndExtensionClasspath(String jreOption) { String jreDir = getJreDir(jreOption); // 加载JRE的bootstrap和extension类路径 bootstrapClasspath = new WildcardEntry(jreDir + File.separator + "lib" + File.separator + "*"); extensionClasspath = new WildcardEntry(jreDir + File.separator + "lib" + File.separator + "ext" + File.separator + "*"); } private String getJreDir(String jreOption) { if (jreOption != null && Files.exists(Paths.get(jreOption))) { return jreOption; } if (Files.exists(Paths.get("./jre"))) { return "./jre"; } String jh = System.getenv("JAVA_HOME"); if (jh != null) { return Paths.get(jh, "jre").toString(); } throw new RuntimeException("无法找到JRE目录"); } private void parseUserClasspath(String cpOption) { if (cpOption == null) { cpOption = "."; } userClasspath = Entry.create(cpOption); } public byte[] readClass(String className) throws Exception { className = className + ".class"; try { return bootstrapClasspath.readClass(className); } catch (Exception e) { // 忽略 } try { return extensionClasspath.readClass(className); } catch (Exception e) { // 忽略 } return userClasspath.readClass(className); }} package org.itstack.demo.jvm.classpath;import org.itstack.demo.jvm.classpath.impl.CompositeEntry;import org.itstack.demo.jvm.classpath.impl.DirEntry;import org.itstack.demo.jvm.classpath.impl.WildcardEntry;import org.itstack.demo.jvm.classpath.impl.ZipEntry;import java.io.File;import java.io.IOException;public interface Entry { byte[] readClass(String className) throws IOException; static Entry create(String path) { if (path.contains(File.pathSeparator)) { return new CompositeEntry(path); } if (path.endsWith("*")) { return new WildcardEntry(path); } if (path.endsWith(".jar") || path.endsWith(".JAR") || path.endsWith(".zip") || path.endsWith(".ZIP")) { return new ZipEntry(path); } return new DirEntry(path); }} 通过运行Main.java可以看到以下输出结果:
classpath:org.itstack.demo.jvm.classpath.Classpath@4bf558aaclass:E:\itstack\git\istack-demo\itstack-demo-jvm\itstack-demo-jvm-02\target\test-classes\org\itstack\demo\test\HelloWorldargs:nullclassData:ca fe ba be 00 00 00 34 00 22 0a 00 06 00 14 09 00 15 00 16 08 00 17 0a 00 18 00 19 07 00 1b 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65 01 00 12 4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 01 00 04 74 68 69 73 01 00 22 4c 6f 72 67 2f 69 74 73 74 61 63 6b 2f 64 65 6d 6f 2f 74 65 73 74 2f 48 65 6c 6c 6f 57 6f 72 6c 64 3b 01 00 04 6d 61 69 6e 01 00 16 28 5b 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 01 00 04 61 72 67 73 01 00 13 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 01 00 0A 53 6F 75 72 63 65 46 69 6C 65 01 00 0F 48 65 6C 6C 6F 57 6F 72 6C 64 2E 6A 61 76 61 0C 00 07 00 08 07 00 1C 0C 00 1D 00 1E 01 00 0D 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 07 00 1F 0C 00 20 00 21 01 00 20 6F 72 67 2F 69 74 73 74 61 63 6B 2F 64 65 6D 6F 2F 74 65 73 74 2F 48 65 6C 6C 6F 57 6F 72 6C 64 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D 01 00 03 6F 75 74 01 00 15 4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B 01 00 13 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 01 00 07 70 72 69 6E 74 6C 6E 01 00 15 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 29 56 00 21 00 05 00 06 00 00 00 00 00 02 00 01 00 07 00 08 00 01 00 09 00 00 00 2F 00 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 02 00 0A 00 00 00 06 00 01 00 00 00 03 00 0B 00 00 00 0C 00 01 00 00 00 05 00 0C 00 0D 00 00 00 09 00 0E 00 0F 00 01 00 09 00 00 00 37 00 02 00 01 00 00 00 09 B2 00 02 12 03 B6 00 04 B1 00 00 00 02 00 0A 00 00 00 0A 00 02 00 00 00 06 00 08 00 07 00 0B 00 00 00 0C 00 01 00 00 00 09 00 10 00 11 00 00 00 01 00 12 00 00 00 02 00 13
通过Notepad++打开HelloWorld.class文件,并使用HEX-Editor插件查看其字节码,可以看到类的具体字节排列。
转载地址:http://ifiaz.baihongyu.com/