本文是对 java 通配符的总结
通配符
泛型的局限性与漏洞
| Pair<Employee> employeePair= new Pair<>(new Employee("员工1"), new Employee("员工2")); | 
完整代码:继承示例
- 无论 S 和 T 有什么关系,Pair<S>和Pair<T>没有什么联系。
- 泛型与原始内容兼容,但是原始内容里的类型参数这个对象无法调用方法
- 泛型里的类型参数可以继承,和类的继承规则一样
? extends Object(上边界限定通配符)
可以看出来原始泛型遇上继承时会有些漏洞,比如会出现经理员工在同一Pair的情况。于是Java专家引入了类型通配符 ?
我们把刚刚的第一行改为:
| Pair<? extends Employee> employeePair= new Pair<>(new Employee("员工1"), new Employee("员工2")); | 
此时,如果再向里面添加	Manager时就会发生错误:
| employeePair.setFirst(new Manager("经理3", 300)); // 错误 | 
但是访问可以:
| Employee employee = employeePair.getFirst(); // 正确 | 
分析
首先永远记住只能超类接收子类!!!反过来不行!!!(这个可以解释下面的一切)
类型擦除 后 Pair<? extends Employee> 的方法有:
| ? extends Employee getFirst() {...} // 访问器 | 
- 访问器的返回值是? extends Employee,可以用子类Employee接收
- 更改器的接收值是? extends Employee,极端情况是Employee的最下面的子类,而最下面的子类只能接收更下面的子类(无),因此 拒绝接收任何特定的类型!
小结
简单说就是:
可以 Employee <-- ? extends Employee ,但是反过来不行!
所以这就是大家说的使用? extends Object 可以 安全的访问泛型对象。我的理解核心是:如果T作为返回值,用? extends Object更安全。
? super Object(下边界限定通配符)
这个和上面正好相反,更改器能用,访问器不能用。
分析
| ? super Employee getFirst() {...} // 访问器 | 
- 访问器的返回值是? super Employee,极端情况是Object,只能用Object接收
- 更改器的接收值是? super Employee,可以接收Employee 和 它的子类
小结
简单说就是:
可以 ? super Employee <-- Employee ,但是反过来不行!
所以这就是大家说的使用? super Object 可以 安全的更改泛型对象。我的理解核心是:如果T作为方法参数,用? super Object更安全。
共同特点
右边的值传给左边接收:
? super Employee <-- Employee <-- ? extends Employee
是不是完全符合 只能超类接收子类,知道原理记起来就简单。
例子
举书上的一个例子作为练习:
| public static <T extends Comparable<? super T>> T min(T[] a) //计算T[]的最小值 | 
理解:
- T extends...好理解,就是- T要实现后面的接口。
- 实现Comparable<? super T>接口里的方法int compareTo(? super T);此时类型作为 方法参数,所以用? super更安全。
?(无限定通配符)
| ? getFirst() {...} // 访问器 | 
- 访问器只能用Object接收
- 更改器不能用
可以用任意Object对象调用原始 Pair类的setObject方法,说白了就是什么类型都能
作为泛型方法的方法参数,但就是不能有返回值。
通配符捕获
由于通配符不能作为类型变量,所以必要时可以用一个辅助的泛型方法。
第一步:辅助泛型方法
| public static <T> void swapHelper(Pair<T> p) | 
第二步:通配符捕获
| public static void swap(Pair<?> p){ swapHelper(p); } | 
示例
完整代码:通配符示例