我有一个遗留(不可修改的:-()代码,它有一个静态初始化程序块。 我想创建一个子类 - 但不运行静态块。
有没有办法做到这一点?例如: class.ForName 方法有一个第二个参数,它负责初始化类 - 但遗憾的是,它对我不起作用(可能意味着别的......):http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#forName(java.lang.String ,boolean,java.lang.ClassLoader)
更新:上面提到的 class.forName 没有触发初始化 - 但是要求 newInstance 会: - (
谢谢, 克里西
答案 0 :(得分:2)
我有一个遗留(不可修改的:-()代码,它有一个静态初始化块。我想创建一个子类 - 但是没有运行静态块。
你可以创建一个子类 - 但你永远不能初始化那个子类,这意味着它可能没用。
从section 12.4.2 of the JLS(类初始化):
接下来,如果C是类而不是接口,并且其超类SC尚未初始化,则递归执行SC的整个过程。
基本上我认为你需要重新考虑设计。理想情况下,您可以应对静态初始化程序的运行。
答案 1 :(得分:2)
您始终可以使用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
}
输出:
空
答案 2 :(得分:0)
您可以执行以下操作:
我知道它不漂亮,但你几乎没有其他选择。静态初始化程序将在加载类之后立即运行,并且不可能跳过它。