java使用了泛型来保证数据的安全性,避免了什么乱七八糟的
东西都往容器里扔的情况。一般情况下我们使用<T>来定义泛型,
例如下面这块代码
public <T> T[] toArray(T[] a)
但是有时我们也会使用<? extends T>和<? super T>,这里简单介绍下
<? extends T>被称为 上界通配符,意为可以存入的类型包括T以及T的子类,例如
1 public T orElseGet(Supplier<? extends T> other) { 2 return value != null ? value : other.get(); 3 }
<? super T> 被称为下界通配符,意为可以存入的类型包括T以及T的父类,例如
1 default Predicate<T> and(Predicate<? super T> other) { 2 Objects.requireNonNull(other); 3 return (t) -> test(t) && other.test(t); 4 }
也有同时使用的情况
1 default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { 2 Objects.requireNonNull(before); 3 return (V v) -> apply(before.apply(v)); 4 }
验证代码如下,我们发现无法将<? extends Father>与GrandFather关联,
同样的,无法将<? super Father>与Child关联
1 public class PorblemSolution { 2 3 public static void main(String[] args){ 4 5 Person<Father> p1 = new Person<Father>(); 6 7 Person<? extends Father> p2 = new Person<Child>(new Child()); 8 Person<? extends Father> p3 = new Person<Father>(new Father()); 9 // Person<? extends Father> p4 = new Person<GrandFather>(new GrandFather()); 10 // Type mismatch: cannot convert from Person<GrandFather> to Person<? extends Father> 11 12 Person<? super Father> p5 = new Person<Father>(new Father()); 13 Person<? super Father> p6 = new Person<GrandFather>(new GrandFather()); 14 // Person<? super Father> p7 = new Person<Child>(new Child()); 15 // Type mismatch: cannot convert from Person<Child> to Person<? super Father> 16 17 } 18 } 19 20 21 class GrandFather{ 22 GrandFather(){}; 23 } 24 25 class Father extends GrandFather{ 26 Father(){}; 27 } 28 29 class Child extends Father{ 30 Child(){}; 31 } 32 33 class Person<T> { 34 35 private T item; 36 37 Person(){}; 38 39 Person(T t){ 40 item = t; 41 } 42 43 public void set(T t){ 44 item=t; 45 } 46 47 public T get(){ 48 return item; 49 } 50 }
<? extends T>和<? super T>为我们使用泛型提供了更多的实现方案,使得泛型的匹配不只局限于T本身。
但是,这两个通配符在使用过程中会泛型中类异常的风险增加,这里可以套用父类子类强制类型转换的思路去理解。
更详细的解释可以看这里https://www.zhihu.com/question/20400700
另外,我们需要知道java中的泛型是伪泛型,是加在编译层面的校验机制,在运行时是没有泛型这个东西的
有兴趣的可以了解下泛型擦除这个机制,这里还是给个样例
1 Person<Father> p1 = new Person<Father>(); 2 Person<? extends Father> p2 = new Person<Child>(new Child()); 3 System.out.println(p1.getClass()); // class JavaTest.Person 4 System.out.println(p2.getClass()); // class JavaTest.Person 5 System.out.println(p1.getClass() == p2.getClass()); // true