java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java虚拟机

利用Java编写一个Java虚拟机

作者:Haidnor

这篇文章主要为大家详细介绍了如何使用 Java17 编写的 Java 虚拟机,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的可以了解下

github 项目链接

https://github.com/FranzHaidnor/haidnorJVM

haidnorJVM

使用 Java17 编写的 Java 虚拟机

意义

主要技术选型

实现功能

局限性

不支持多线程

不支持多维数组

暂无双亲委派机制实现

无垃圾收集器实现。垃圾回收依靠宿主 JVM

快速体验

你需要准备什么

配置 haidnorJVM

配置日志输出级别

在 resources\simplelogger.properties 文件中修改日志输出级别,一般使用 debuginfo

public class Demo5 {
    public static void main(String[] args) {
        String str = method1("hello world");
        method1(str);
    }
    public static String method1(String s) {
        return method2(s);
    }
    public static String method2(String s) {
        return method3(s);
    }
    public static String method3(String s) {
        System.out.println(s);
        return "你好 世界";
    }
}

每一个  结构图形,都表示一个 JVM 线程栈中的栈帧

配置 rt.jar 路径

修改 haidnorJVM.properties 文件中的内容。配置 rt.jar 的绝对路径,例如rt.jar=D:/Program Files/Java/jdk1.8.0_361/jre/lib/rt.jar

运行单元测试用例

在 IDE 中打开项目中 test 目录下的 haidnor.jvm.test.TestJVM.java 文件。 这是 haidnorJVM 的主要测试类, 里面的测试方法可以解析加载运行 .class 字节码文件。

public class TestJVM {
   /**
    *  haidnorJVM 会加载 HelloWorld.java 在 target 目录下的编译后的字节码文件,然后运行其中的 `main(String[] args)` 方法。
    *  你可以使用打断点的方式看到 haidnorJVM 是如何解释运行 Java 字节码的。
    *  值得注意的是,这种方式编译运行的字节码文件是基于 java17 版本的。
    */
   @Test
   public void test() {
      runMainClass(HelloWorld.class);
   }
}

运行 .class 文件

public class HelloWorld {
   public static void main(String[] args) {
     System.out.println("HelloWorld");
   }
}

运行 .jar 文件

存在的问题

由于 haidnorJVM 目前运行 JDK 自带的类是使用反射解决的,因此 haidnorJVM 使用 JDK17 运行部分 JDK 自带的类时会存在一些问题,例如运行以下代码将会抛出异常

public class Demo {
    public static void main(String[] args) {
        List<Integer> list = List.of(1, 2, 3, 4, 5);
        list.add(6);
    }
}
java.lang.reflect.InaccessibleObjectException: Unable to make public boolean java.util.ImmutableCollections$AbstractImmutableCollection.add(java.lang.Object) accessible: module java.base does not "opens java.util" to unnamed module @18769467
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
	at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)

它表示尝试通过反射来访问一个方法或字段,但该方法或字段的可访问性限制导致无法访问。

这个限制通常是由于 Java 模块系统引起的。模块系统允许将代码划分为独立的模块,并控制模块之间的访问权限。以上异常的原因是 module java.base does not "opens java.util" to unnamed module,也就是说 java.base 模块没有向未命名模块开放 java.util 包

解决方法:启动 haidnorJVM 时添加 JVM 参数 --add-opens java.base/java.util=ALL-UNNAMED 绕过访问性限制

以上就是利用Java编写一个Java虚拟机的详细内容,更多关于Java虚拟机的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文