假设有 3 个类, 他们的继承关系是这样的

1
2
public class Person {
}
1
2
public class Gril extends Person {
}
1
2
public class Boy extends Person {
}
1
2
public class Father {
}

在类上指定的泛型, 那么在当前类, 使用的都是这个对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class MyTest<T> {
		
		public void println(T t){
					 System.out.println(t.getClass().getSimpleName());
		}

    public static void main(String[] args) {
				        new MyTest<Person>(); // 打印的是 Person
        				new MyTest<Gril>(); // 打印的是 Gril
    }
}

方法上面的泛型

1
2
3
 public static <T extends Person> void println1(T t) {
        System.out.println(t.getClass().getSimpleName());
 }

泛型的上限和下限

1
2
<T extends Person>  泛型上限, 只能是 Person 或者是 Person 的子类
<T super Person>    泛型下限, 只能是 Person 或者是 Person 的父类

泛型通配符: 表示可接受一切类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
ArrayList<Boy> arrayList1 = new ArrayList<>();
ArrayList<Gril> arrayList2 = new ArrayList<>();
ArrayList<Person> arrayList3 = new ArrayList<>();
ArrayList<Father> arrayList4 = new ArrayList<>();

println1(arrayList1);
println1(arrayList2);
println1(arrayList3);
println1(arrayList4);

public static void println1(List<?> t) {
     System.out.println(t.getClass().getSimpleName());   
}

泛型擦除

1
2
3
4
5
6
7
8
ArrayList<String> list1 = new ArrayList<String>();
list1.add("abc");

ArrayList<Integer> list2 = new ArrayList<Integer>();
list2.add(123);

// 打印的结果为 true 类型一致, 这就是泛型擦除
System.out.println("类型是否一致 " + (list1.getClass() == list2.getClass())); 

这里的结果为什么会为 true 呢? 这就是因为泛型在编译时期就被擦除了, 他们在编译后都是 List 类型相等, 所以为 true, 这个时候如果我们在手写代码的时候, 如果是添加其他的类型仍然会报错, 这个又是为什么呢 ? 这是因为, 其实是在编译之前, 编译器会帮我们检查类型是否是一致的, 避免发生强转失败的现象

最后再看一个现象

1
2
3
ArrayList<? extends Person> arrayList = new ArrayList<>();
arrayList.add(new Person()); // 报错
arrayList.add(new Boy()); // 报错

不能够添加, 这个是为什么 ? 这个因为虽然你使用了通配符接受了继承至 Person 的任意类型, 但是其实编译器并不知道你的 arrayList 是具体的那一个类型的, 所以不能添加, 其实和你写 <? extends Object> 是一样的, 编译器并不能够确定是具体的那一个类型, 那接着只需要简单修改一下, 就不会再报错了

1
2
3
4
ArrayList<? super Person> arrayList = new ArrayList<>();
arrayList.add(new Person()); 
arrayList.add(new Boy());  
//arrayList.add(new Father()); // 报错, 因为 Father 不是 Person 的子类

这样就不会报错了, 这又是为什么呢 ? 其实当这个时候, 规则是泛型下限, 只能够接受 Person 的父类, 这个时候就能够确定要添加的类型了, 那么也就意味着, arrayList 添加子类是肯定没有问题的, 只要父类出现的地方, 子类一定能够出现, 这也遵循了一大原则: 里氏替换原则