Viv*_*vek 2 java jvm bytecode javac .class-file
我想使用某种编辑器打开由Java Compiler生成的字节代码(Java二进制文件),这允许我查看字节代码(Raw,但人类可以理解,采用此处定义的格式)并直接修改.class
文件中的内容.
我试过这个javap
实用程序.但通过javap
,我无法更改我的.class文件,它似乎也没有显示原始字节代码
此外,我已经看到像JD Decompiler这样的反编译器,它给了我来自.class
File 的代码.但我对源代码不感兴趣,我想查看字节码.
另外,我尝试过名为dirtyJOE&JBE的 GUI编辑器.这个编辑器非常好,完成了我的目的的一半.我可以在.class
文件中看到各种字段并编辑我的.class
文件.但这似乎也就像一个翻译器,它解码字节码并在UI上显示它以便于理解.它没有显示原始字节代码.
甚至可以转到原始字节码?
我可能听起来很愚蠢,但我想确认这一点,以正确理解Java编译器和JVM.
可以转储原始字节代码,javap -v
但要以您可以编辑的格式获取类文件中的所有信息,我使用ASM.你不会用它来编辑的原因是;
它的价值不在于字节代码只是为Java代码编译的,这就是为什么它们做同样的事情.JVM可以通过多种方式自由地优化它,这使得如果您想了解JVM的工作原理或代码运行方式,理解字节代码并不是非常有用.
感谢@Antimony建议用于手动编写的字节代码.虽然它们中的一些是有效的,但它们要么相当先进或模糊,要么有另一种方法来实现同样的目的.
一些想法
抛出已检查的异常而不声明它们,
Thread.currentThread().stop(checkedException);
Run Code Online (Sandbox Code Playgroud)
捕获已检查的异常而不声明它们,
if (false) throw new CheckedException();
} catch(CheckedException ce) {
Run Code Online (Sandbox Code Playgroud)
在Java中使用标识符无效
有许多有效但不太有用的字符可供我使用其中之一
if( ? ? ? == ? ? ? || ¢ + ?== ?)
Run Code Online (Sandbox Code Playgroud)
和
for (char c??h = 0; c??h < Character.MAX_VALUE; c??h++)
if (Character.isJavaIdentifierPart(c??h) && !Character.isJavaIdentifierStart(c??h))
System.out.printf("%04x <%s>%n", (int) c??h, "" + c??h);
Run Code Online (Sandbox Code Playgroud)
由于标识符中的不可见字符导致文本向后打印,因此是有效代码.
http://vanillajava.blogspot.co.uk/2012/09/hidden-code.html
http://vanillajava.blogspot.co.uk/2012/08/uses-for-special-characters-in-java-code.html
在构造函数调用之前访问字段
我很确定这会导致VerifyError(或者当我尝试它时它会执行).相反,你可以使用
Object o = Unsafe.allocateInstance(clazz); // create without calling a constructor.
Run Code Online (Sandbox Code Playgroud)
有条件地调用不同的构造函数
我再次能够在对象创建和实例调用之间放置代码,但可能有一种方法可以让它工作.在Java中你会写
MyClass mc = condition ? new MyClass(a) : new MyClass(a, b);
Run Code Online (Sandbox Code Playgroud)
在构造函数上进行异常处理.
不知道你在这里是什么意思,因为你可以在构造函数中捕获或抛出异常.
分配最终字段不止一次或根本不分配
您可以使用反射,并将最终字段设为默认值.即一个领域不可能没有价值.
有一个带有nonstrictfp方法的strictfp构造函数
这是一个有趣的,但不是我需要的.
使用laxer类型检查
字节代码允许不同的类型检查规则,但它们很容易与不那么有用的VerifyErrors相悖.你可以做到这一点,但很难得到正确的恕我直言.
从静态初始化器中抛出异常
你可以抛出未经检查的异常,并抛出已检查的异常,你可以使用上面的技巧,但我通常用AssertionError等包装.
使用invokedynamic
您可以使用MethodHandles但它们在Java 7中相当笨重.我希望在Java 8中它们更自然地使用.
使用子程序
有趣的是,我没有试过这个,但我不确定他们会给方法调用带来什么好处.
使用异常控制流程
没错,但这更容易混淆JIT优化器,因此代码可能会因此而变慢,因此可能无法为您提供您可能希望的优势.
使用旧的超级调用语义
你可以,但我不确定它是多么有用.
使用线程监视器
您可以使用
Unsafe.enterMonitor();
Unsafe.exitMonitor();
Unsafe.tryMonitorEnter();
Run Code Online (Sandbox Code Playgroud)
字段的初始值.
我同意编译器没有像我期望的那样使用这些,但是我不确定它们如果有的话会有什么不同.