Skip to content

泛型

Javassist的低级API完全支持Java 5引入的泛型。另一方面,像CtClass这样的高级API并不直接支持泛型。然而,对于字节码转换来说,这不是一个严重的问题。Java的泛型是通过擦除技术实现的。编译后,所有类型参数将被删除。例如,假设你的源代码声明了一个参数化类型Vector< String >:

java
Vector<String> v = new Vector<String>();
:
String s = v.get(0);

编译后的字节码相当于以下代码:

java
Vector v = new Vector();
  :
String s = (String)v.get(0);

当你写字节码转换器时,你可以去掉所有类型参数。由于Javassist中嵌入的编译器不支持泛型,因此如果源代码是由Javassist编译的,例如通过CtMethod.make(),则必须在调用者站点插入显式类型转换。如果源代码是由javac等普通Java编译器编译的,则不需要类型强制转换。例如,如果你有一个类:

java
public class Wrapper<T> {
  T value;
  public Wrapper(T t) { value = t; }
}

并且想要给类Wrapper< T >添加一个接口Getter< T >:

java
public interface Getter<T> {
  T get();
}

那么你真正需要添加的接口是Getter(类型参数< T >消失了),你还必须添加到Wrapper类的方法是这个简单的:

java
public Object get() { return value; }

注意,不需要任何类型参数。由于get返回一个Object,如果源代码是由Javassist编译的,则需要在调用者站点进行显式类型转换。例如,如果类型参数T为String,则必须按如下方式插入(String):

java
Wrapper w = ...
String s = (String)w.get();

如果源代码是由普通Java编译器编译的,则不需要类型强制转换,因为它会自动插入类型强制转换。

如果需要在运行时通过反射访问类型参数,则必须向类文件添加泛型签名。要了解更多细节,请参阅CtClass中setGenericSignature方法的API文档(javadoc)。

Released under the MIT License.