5

我正在开发一个项目,该项目需要我在旅途中生成一个 java“.class”文件,以后可以在 JVM 上编译该文件。在学习和使用 MSIL (Microsoft IL) 这也是一种基于堆栈的中间编程语言之后,以下是我面临的问题:

  1. 与 IL(对于 C# 或 VB)相比,“.class”文件中的 java 字节码以结构化方式包含信息,据我所知,它包含除程序数据之外的元数据,是真的吗? ? 我可以为每个类文件以模板形式生成相同的吗?
  2. 是否必须以二进制格式生成类文件?

我参考了“Joshua Engel 的 Java™ 虚拟机编程”,但它并没有达到我的目的,因为我已经了解了 JVm 指令集。

有人可以帮我吗?所有帮助将不胜感激。生成简单类文件的示例将非常有帮助,因为我还找不到单个 1。

4

5 回答 5

4

使用IKVM Java-to-.NET 编译器ASM 字节码库转换为与 .NET 一起使用的示例:

你好.cs:

using System;
using System.IO;
using org.objectweb.asm;

namespace test.helloWorld
{
    public class helloDump
    {

        public static byte[] dump ()
        {

            ClassWriter cw = new ClassWriter(0);
            MethodVisitor mv;

            cw.visit(Opcodes.__Fields.V1_6, Opcodes.__Fields.ACC_PUBLIC + Opcodes.__Fields.ACC_SUPER, "hello", null, "java/lang/Object", null);

            mv = cw.visitMethod(Opcodes.__Fields.ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            mv.visitVarInsn(Opcodes.__Fields.ALOAD, 0);
            mv.visitMethodInsn(Opcodes.__Fields.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mv.visitInsn(Opcodes.__Fields.RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();

            mv = cw.visitMethod(Opcodes.__Fields.ACC_PUBLIC + Opcodes.__Fields.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
            mv.visitCode();
            mv.visitFieldInsn(Opcodes.__Fields.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("Hello World!");
            mv.visitMethodInsn(Opcodes.__Fields.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
            mv.visitInsn(Opcodes.__Fields.RETURN);
            mv.visitMaxs(2, 1);
            mv.visitEnd();

            cw.visitEnd();

            return cw.toByteArray();
        }

        public static void Main(string[] args)
        {
            FileStream helloWorldFile = new FileStream("hello.class", FileMode.Create);
            byte[] helloWorldClass = dump();
            helloWorldFile.Seek(0, SeekOrigin.Begin);
            helloWorldFile.Write(helloWorldClass, 0, helloWorldClass.Length);
        }
    }
}

命令:

$ ikvmc -out:org.objectweb.asm.dll -target:library -version:3.2.0.0 asm-3.2.jar
$ mcs -r:org.objectweb.asm.dll  hello.cs
$ mono hello.exe
$ ls hello.class
$ java hello
于 2009-11-25T18:18:49.723 回答
2

您可能想查看ASM字节码库。它很受欢迎。许多 JVM 语言都使用它:Clojure、Groovy、Jython、JRuby。

但我确实同意其他发帖人的观点,即生成 Java 源代码并对其进行编译以获取您的 .class 文件可能更简单。javac很大程度上取决于你需要做什么。

于 2009-11-25T16:19:41.960 回答
0

你看过BCEL吗?

http://en.wikipedia.org/wiki/Byte_Code_Engineering_Library

它现在与 JRE 捆绑在一起。

于 2009-11-25T16:12:02.613 回答
0

将以下内容保存到命令行Simple.javajavac Simple.java从命令行执行(假设您已安装 JDK)

public class SimpleJava {
  public static main(String[] args) {
    System.out.println("Big Sorry, couldn't stop myself ;-)");
  }
}

这至少是生成简单类文件的标准方法;)

于 2009-11-25T16:16:01.437 回答
0

认真的回答。

我会自动生成 Java 代码并使用 Java 编译器生成类文件。这看起来比与BCEL作战要容易得多。至少因为用“高级”语言编写算法比使用 Java 字节码更容易。

任何其他产生字节码的编程语言都可以,但我猜 Java 是最简单的方法之一。

来回答你的问题,

(1) 是的,一些元数据是相当静态的。维基百科对类文件格式有一个很好的概述

(2) 是的,类文件是“二进制”。java字节码没有字母数字语言(如汇编程序)(至少我没有听说过任何这样的工具,javap可以打印可读的字节码但没有退路)

编辑

仍然很难猜测,您真正想要做什么,但以防万一,您想围绕一个算术表达式编写一个类文件,该类文件可以在 Java 虚拟机中评估该算术表达式,那么您真的可以从创建一个模板类文件开始.

在这种情况下,我会用 Java 编写这个“评估器”并对其进行测试,直到它评估所有有效输入。我会使用一个私有字段来保存表达式,用一个虚拟表达式初始化。

我的 Java 编码评估器的类文件将是“动态”类生成的完美模板 - 我只需要找出如何用真实表达式“替换”虚拟表达式,重新创建有效的类文件(您可能需要调整一些指针因为不同的字符串长度),它应该工作。

即使这个猜测是完全错误的,它也可以作为案例研究,并可以帮助你:)

于 2009-11-25T16:19:18.433 回答