Java泛型:
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
从上面的描述中我么可以知道,Java泛型时作用在编译时期的,用来提供安全检测和规范代码,并且在运行期,就没有所谓的泛型,这是因为jvm对其进行了泛型擦出操作
测试代码:
public class Main {
public static void main(String[] args) {
List list = new ArrayList<>();
List<Object> obj = new ArrayList<Object>();
System.out.println(list.getClass()==obj.getClass());
}
}
运行结果:true
这也就说明了在运行期,泛型擦出操作是存在的
Java反射:
java中提供的一套类库,通过这套类库
-运行时动态获取类的信息
-运行时动态调用构造函数创建对象
-运行时动态访问(调用)对象的方法或属性
java反射实在程序运行时期所进行的操作,用来获取和操作类的信息(包括构造函数,属性和方法)
但是,如果使用反射对泛型进行操作会怎样呢?
测试代码:
import java.util.List;
import java.util.Map;
public class Demo {
public void getList(List<Person> list){
}
public void getMap(Map<String,Person> map){
}
}
class Person{}
测试类:
import java.lang.reflect.Method;
import java.lang.reflect.Type;
public class Test {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("test.Demo");
Method[] methods = clazz.getDeclaredMethods();
for(Method m:methods){
Type[] type = m.getGenericParameterTypes();//获取参数类型
for(Type t:type){
System.out.println(t);
}
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
运行结果:
可以看到,程序打印出的方法中参数类型的信息,还打印出了他们泛型的信息
原因:
在周志明写的深入理解java虚拟机中有这样一段话:
Signature属性在JDK 1.5发布后增加到了Class文件规范之中,它是一个可选的定长属性,可以出现于类、属
性表和方法表结构的属性表中。在JDK 1.5中大幅增强了Java语言的语法,在此之后,任何类、接口、初始化方法
或成员的泛型签名如果包含了类型变量(Type Variables)或参数化类型(Parameterized Types),则Signature
属性会为它记录泛型签名信息。之所以要专门使用这样一个属性去记录泛型类型,是因为Java语言的泛型采用的是
擦除法实现的伪泛型,在字节码(Code属性)中,泛型信息编译(类型变量、参数化类型)之后都通通被擦除掉。
使用擦除法的好处是实现简单(主要修改Javac编译器,虚拟机内部只做了很少的改动)、非常容易实现
Backport,运行期也能够节省一些类型所占的内存空间。但坏处是运行期就无法像C#等有真泛型支持的语言那样,
将泛型类型与用户定义的普通类型同等对待,例如运行期做反射时无法获得到泛型信息。Signature属性就是为了
弥补这个缺陷而增设的,现在Java的反射API能够获取泛型类型,最终的数据来源也就是这个属性。
综上所述,泛型擦出的确存在,但是在JDK1.5之后,又出现了一个名为Signature的属性,用它来标识泛型的相关信息