我有一个界面,如:
public interface Foo() {
public void bar();
}
我想创建一个实现它的匿名枚举,就好像这是有效的Java:
public enum MyEnum {
A implements Foo {
public void bar() {
System.out.println("Hello!");
}
},
B,
C;
}
(注意只有A实现Foo,而不是B或C.)
(这与那些" Java字节码中你可以用Java做什么?"问题。)
答案 0 :(得分:2)
确实可以通过字节码操作创建这样的类文件。这是一个使用ASM库执行此操作的示例程序:
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.objectweb.asm.*;
public class EnumHack {
interface Foo {
public void bar();
}
enum MyEnum {
A {
public void bar() {
System.out.println("Hello!");
}
},
B,
C;
}
public static void main(String... arg) {
try {
patch();
} catch (IOException|URISyntaxException ex) {
System.err.println("patching failed: "+ex);
return;
}
test();
}
static void test() {
for(MyEnum e: MyEnum.values()) {
System.out.println(e.name());
if (e instanceof Foo) {
System.out.println("\timplements Foo");
((Foo)e).bar();
}
}
}
static void patch() throws IOException, URISyntaxException {
URL url = MyEnum.class.getResource("EnumHack$MyEnum$1.class");
ClassReader cr=new ClassReader(url.openStream());
ClassWriter cw=new ClassWriter(cr, 0);
cr.accept(new ClassVisitor(Opcodes.ASM5, cw) {
@Override
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
if(interfaces.length==0) // not patched yet
interfaces=new String[] { Foo.class.getName() };
super.visit(version, access, name, signature, superName, interfaces);
}
}, 0);
Files.write(Paths.get(url.toURI()), cw.toByteArray());
}
}
打印
A
implements Foo
Hello!
B
C
在Oracles的Java 8下运行时,类文件驻留在文件系统中。当在不同的JVM下运行或捆绑在Jar文件中时,回写修改后的类文件可能会失败,或者enum
可能已经急切地加载而不反映修改(但它会在下次运行时)。
但它表明,通常情况下,字节码操作是可能的,并且在启动应用程序之前执行时,它甚至可以在更复杂的场景中工作。
尽管如此,我认为这只是一个有趣的有趣的黑客,但你不应该建立应用程序。没有问题,这个hack将解决你无法使用实现接口的委托对象解决...