所有可能的Java代码都可能通过字节码生成。
我对cglib并不熟悉,但这里有一些asm代码可以完成你所要求的功能。
唯一与泛型相关的特殊部分它是genericSig()
方法,它为除了原始形态Type.getInternalName(Foo.class)
之外的超类定义“第二个签名”。
这不是一个通用的解决方案,它会为问题中的示例创建字节码。对于一般的解决方案,还需要考虑许多其他事情,特别是桥接方法。
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.signature.SignatureVisitor;
import org.objectweb.asm.signature.SignatureWriter;
public class GenExtendFoo {
public static void main(String[] args) throws Exception {
ClassWriter cw = new ClassWriter(0);
/** Extend Foo with normal raw superclass "com/Foo"
And generic superclass genericSig() Lcom/Foo<Ljava/lang/Integer;>;
**/
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "SubClass", genericSig(Foo.class, Integer.class),
Type.getInternalName(Foo.class), new String[] {});
createConstructor(cw);
cw.visitEnd();
byte[] b = cw.toByteArray();
Class<?> cls = (Class<?>) new MyClassLoader().defineClass("SubClass", b);
Foo<Integer> instance = (Foo<Integer>) cls.getConstructor(Integer.class).newInstance(1);
System.out.println(instance.getValue());
/* The generic type is available with GenericSuperclass just like in the plain java version */
ParameterizedType para = (ParameterizedType) instance.getClass().getGenericSuperclass();
System.out.println(para.getActualTypeArguments()[0]);
}
private static void createConstructor(ClassWriter cw) {
// Create constructor with one parameter that calls superclass
// constructor with one parameter
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
"(L" + Type.getInternalName(Integer.class) + ";)V", null, null);
mv.visitMaxs(2, 2);
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Foo.class), "<init>",
"(L" + Type.getInternalName(Object.class) + ";)V", false); // call
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
}
public static String genericSig(Class<?> mainType, Class<?> typeParameter) {
SignatureVisitor sv = new SignatureWriter();
SignatureVisitor psv = sv.visitSuperclass();
psv.visitClassType(Type.getInternalName(mainType));
SignatureVisitor ppsv = psv.visitTypeArgument('=');
ppsv.visitClassType(Type.getInternalName(typeParameter));
ppsv.visitEnd();
psv.visitEnd();
return sv.toString();
}
}
static class MyClassLoader extends ClassLoader {
public Class<?> defineClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
}
你想在运行时generare源代码,或者类? – NickL
我宁愿在运行时即时创建类。如果我必须生成源代码,然后在运行时加载源代码,那么这是第二好的选择...... – Jason
那么......由于类型擦除,'generic A'类型在运行时将是'Object'类型。 – NickL