ASM으로 이전 클래스를 항상 패치 할 수 있습니다. clinit 블록을 무시하여 이전 바이트 코드에서 새 클래스를 생성하는 것은 쉬워야합니다. 여기
import org.objectweb.asm.*;
import org.objectweb.asm.commons.EmptyVisitor;
import java.io.*;
public class ClinitKiller {
public static void main (String[] args) {
final InputStream input = ClinitKiller.class.getResourceAsStream(Test.class.getName() + ".class");
try {
final byte[] bytes = instrument(input);
FileOutputStream out = new FileOutputStream("/tmp/Test.class");
out.write(bytes);
out.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
public static byte[] instrument(InputStream is) throws IOException {
ClassReader reader = new ClassReader(is);
ClassWriter writer = new ClassWriter(0);
ClinitKillerClassAdapter classAdapter = new ClinitKillerClassAdapter(writer);
reader.accept(classAdapter, 0);
return writer.toByteArray();
}
}
class ClinitKillerClassAdapter extends ClassAdapter {
public ClinitKillerClassAdapter(final ClassVisitor cv) {
super(cv);
}
public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
if (name.equals("<clinit>")) {
return new EmptyVisitor();
}
return cv.visitMethod(access, name, desc, signature, exceptions);
}
}
는 전후 인 다음 클래스 :
public class Test {
private static final String value;
static {
System.out.println("Test static");
value = "test value";
}
public static void main(String[] args) {
System.out.println(value);
}
}
전 :
javap -c Test
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: getstatic #3; //Field value:Ljava/lang/String;
6: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
9: return
static {};
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldC#5; //String Test static
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: ldC#6; //String test value
10: putstatic #3; //Field value:Ljava/lang/String;
13: return
}
출력 :
시험 정적
테스트 값
따고 :
javap -c Test
Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #11; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #21; //Field java/lang/System.out:Ljava/io/PrintStream;
3: getstatic #23; //Field value:Ljava/lang/String;
6: invokevirtual #29; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
9: return
}
출력 :
널 (null)
출처
2013-01-23 10:12:03
jdb
제가 투표를했습니다,하지만 제 생각에는 예제를 제공해야한다고 생각합니다. – CAMOBAP
감사합니다. – krisy