JAVA中泛型简单讲就是将类型参数化,可以用在类、接口和方法。

泛型类:

1
2
3
4
5
6
public class ClassA<T> {

public void print(T t) {
System.out.println("class is" + t.getClass());
}
}

泛型接口:

1
2
3
4
interface IA<T> {

T getThing();
}

泛型方法:

1
2
3
public <T> void print(T t) {
System.out.println("class is" + t.getClass());
}

泛型只在编译期有效,编译后生成的字节码中不包含泛型信息,也就是在编译结束后泛型被去除了。即泛型擦除。泛型被擦除后变成了什么呢?

1
2
3
ArrayList<Integer> listA = new ArrayList<>();
listA.add(12);
System.out.println("listA type is" + (listA.get(0).getClass()));

运行结果:

listA type isclass java.lang.Integer

listA编译后泛型转化成了实际对象类型Integer,也就是自动类型转换。

  • 有界通配符

MyClass<? extends Number> 有上限,须继承Number类;

MyClass<? super String>有下限,须是String类的父类,如Object

  • 静态方法不能使用类定义的泛型,因为静态方法调用时,类还没有初始化,且方法在栈中,类的实例化在堆区。

泛型带来的问题:

1.泛型会经过先类型检查再编译,类型检查针对的是引用;

1
2
3
4
5
6
7
ArrayList<String> list = new ArrayList<>();
list.add(12);//报错 编译不能通过
String s = list.get(0);//返回的是String类型

ArrayList list1 = new ArrayList<String>();
list1.add(12);//编译通过
Object ob1 = list1.get(0);//返回的是Object

2.引用传递;

1
2
3
4
ArrayList<String> list = new ArrayList<>();
t1(list);//编译不通过,类型检测ArrayList<String>与ArrayList<Object>数组结构不一样
private void t1(ArrayList<Object> l) {
}

泛型类型继承规则与普通类继承关系不一样的一点。
3.类型擦除与多态的冲突,如在父类中泛型方法,子类实现的对应方法泛型换作具体类型,在该过程中系统为我们生成了桥方法;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//创建接口IFanSheDuoTai,申明方法,方法参数类型是泛型T;
public interface IFanSheDuoTai<T> {

public void test(T t);

}

//实现类FanSheDuoTai 重写方法test
public class FanSheDuoTai implements IFanSheDuoTai<String> {

public static void main(String[] args) {

}

@Override
public void test(String s) {

}
}

反编译FanSheDuoTai.class

javap -p FanSheDuoTai.class

1
2
3
4
5
6
public class com.litchi.demo.FanSheDuoTai implements com.litchi.demo.IFanSheDuoTai<java.lang.String> {
public com.litchi.demo.FanSheDuoTai();
public static void main(java.lang.String[]);
public void test(java.lang.String);
public void test(java.lang.Object);
}

FanSheDuoTai反编译得到的方法可以看到有test(String)和test(Object),test(Object)就是在泛型编译完成后的桥方法

4.泛型不能是基本数据类型;

5.Gson在运行时使用常量池中泛型标签信息解析数据到泛型;

1
Type componentType = ((GenericArrayType)type).getGenericComponentType();

6.静态方法不能使用类定义的泛型,因为在静态方法调用时,类对象可能还没有实例化,类定义泛型是在类实例化时执行,所在的内存区域也是不一样的。

感谢

https://www.cnblogs.com/huansky/p/8043149.html
https://stackoverflow.com/questions/937933/where-are-generic-types-stored-in-java-class-files