Java 如何避免运行静态初始值设定项?
我有一个遗留(不可修改的:-()代码,它有一个静态初始值设定项块。 我想创建一个子类,但不运行静态块 有什么方法可以做到这一点吗?例如:class.ForName方法有第二个参数,它负责初始化类-但遗憾的是,它对我不起作用(可能意味着其他东西:),boolean,java.lang.ClassLoader) 更新:上面提到的class.forName不会触发初始化-但请求新实例会:-( 谢谢, 克里斯蒂 我有一个遗留(不可修改的:-()代码,它有一个静态初始值设定项块。我想创建一个子类,但不运行静态块 您可以创建一个子类,但您永远无法初始化该子类,这意味着它可能是无用的 从(类初始化): 接下来,如果C是一个类而不是一个接口,并且它的超类SC还没有初始化,那么递归地为SC执行整个过程Java 如何避免运行静态初始值设定项?,java,static-methods,Java,Static Methods,我有一个遗留(不可修改的:-()代码,它有一个静态初始值设定项块。 我想创建一个子类,但不运行静态块 有什么方法可以做到这一点吗?例如:class.ForName方法有第二个参数,它负责初始化类-但遗憾的是,它对我不起作用(可能意味着其他东西:),boolean,java.lang.ClassLoader) 更新:上面提到的class.forName不会触发初始化-但请求新实例会:-( 谢谢, 克里斯蒂 我有一个遗留(不可修改的:-()代码,它有一个静态初始值设定项块。我想创建一个子类,但不运行
基本上,我认为您需要重新考虑设计。理想情况下,这样您可以处理运行的静态初始值设定项。您可以始终使用修补程序修补旧类。通过忽略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);
}
}
之前:
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.java”编译而来
公共类测试扩展了java.lang.Object{
公开考试();
代码:
0:aload_0
1:invokespecial#1;//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:getstatic#2;//字段java/lang/System.out:Ljava/io/PrintStream;
3:getstatic#3;//字段值:Ljava/lang/String;
6:invokevirtual#4;//方法java/io/PrintStream.println:(Ljava/lang/String;)V
9:返回
静态{};
代码:
0:getstatic#2;//字段java/lang/System.out:Ljava/io/PrintStream;
3:ldc#5;//字符串测试静态
5:invokevirtual#4;//方法java/io/PrintStream.println:(Ljava/lang/String;)V
8:ldc#6;//字符串测试值
10:putstatic#3;//字段值:Ljava/lang/String;
13:返回
}
输出:静态测试
测试值
之后:
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
}
javap-c测试
从“Test.java”编译而来
公共类测试扩展了java.lang.Object{
公开考试();
代码:
0:aload_0
1:invokespecial#11;//方法java/lang/Object。“:()V
4:返回
公共静态void main(java.lang.String[]);
代码:
0:getstatic#21;//字段java/lang/System.out:Ljava/io/PrintStream;
3:getstatic#23;//字段值:Ljava/lang/String;
6:invokevirtual#29;//方法java/io/PrintStream.println:(Ljava/lang/String;)V
9:返回
}
输出:空您可以执行以下操作:
- 反编译类(例如,使用JAD)
- 删除静态初始值设定项代码
- 编译新类
- 将新类复制到旧代码的jar中(删除旧类)
- 创建你的子类
我知道这并不漂亮,但你几乎没有其他选择。静态初始值设定项将在类加载后立即运行,并且不可能跳过它。好吧,我可以将静态初始值设定项写入子类,以-真正的问题是,如果我创建子类,我不希望父类的静态初始值设定项运行:-)我在考虑将父类包装到另一个类的字段中(例如decorator模式),但是静态初始值设定项也是这样运行的:-(@krisy:Yes-基本上初始值设定项将以任何实际使用该类的方式运行。因此,要么不使用它,要么找到某种方法来处理初始值设定项的运行。
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
}