/**
* 这样做的一个不好的是Box里面现在只能装入String类型的元素,今后如果我们需要装入Integer等其他类型的元素,
* 还必须要另外重写一个Box,代码得不到复用,使用泛型可以很好的解决这个问题。
*/
public class Box {
private String object;
public void set(String object) {
this.object = object;
}
public String get(){
return object;
}
}
使用泛型
public class GenericBox<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
限定通配符和非限定通配符
限定通配符
限定通配符对类型进行了限制。有两种限定通配符:
一种是<? extends T>它通过确保类型必须是T及T的子类来设定类型的上界,
另一种是<? super T>它通过确保类型必须是T及T的父类设定类型的下界。
泛型类型必须用限定的类型来进行初始化,否则会导致编译错误。
非限定通配符
表示了非限定通配符,因为
可以用任意类型来替代。
public class BoundaryCharExample {
//查找一个泛型数组中大于某个特定元素的个数
public static <T> int countGreaterThan(T[] array,T elem){
int count = 0;
for (T e : array) {
if (e > elem) { // compiler error
++count;
}
}
return count;
}
/*
* comliler error:但是这样很明显是错误的,
* 因为除了short, int, double, long, float, byte, char等原始类型,
* 其他的类并不一定能使用操作符" > "
* 解决 --> 使用限定通配符/边界符
* */
}
使用限定通配符改进
public class BoundaryCharExample2 {
public static <T extends Comparable<T>> int countGreaterThan(T[] array,T elem){
//<T extends Comparable<T>>就是通配符,类型必须是 Comparable<T>及其子类
int count = 0;
for (T e : array) {
if (e.compareTo(elem)>0) {
++count;
}
}
return count;
}
}
面试题:List<? extends T> 和List <? super T>之间有什么区别 ?
List<? extends T>可以接受任何继承自T的类型的List,
List<? super T>可以接受任何T的父类构成的List。 例如List<? extends Number>可以接受List
或List
。
/**
* 对于实现了<? extends T>的集合类只能将它视为Producer向外提供(get)元素,
* 而不能作为Consumer来对外获取(add)元素。
*/
public class GenericReading {
private List<Apple> apples = Arrays.asList(new Apple());
private List<Fruit> fruit = Arrays.asList(new Fruit());
private class Reader<T>{ //Reader<T> 是自定义的泛型类
/*T readExact(List<T> list){
return list.get(0);
}*/
T readExact(List<? extends T> list){// 使用通配符来解决这个问题
// ? extends T 表示 T 及 T 的子类
return list.get(0); //TODO :get()方法
}
}
@Test
public void test(){
Reader<Fruit> fruitReader=new Reader<Fruit>();
//Fruit f=fruitReader.readExact(apples);
// 使用 readExact(List<T> list)
// Errors: List<Fruit> cannot be applied to List<Apple>.
Fruit f=fruitReader.readExact(apples);//正确
System.out.println(f);
}
}
/**
*
使用super的坏处是以后不能get容器里面的元素了,
原因很简单,我们继续从编译器的角度考虑这个问题,
对于List<? super Apple> list,它可以有下面几种含义:
List<? super Apple> list = new ArrayList<Apple>();
List<? super Apple> list = new ArrayList<Fruit>();
List<? super Apple> list = new ArrayList<Object>();
当我们尝试通过list来get一个Apple的时候,可能会get得到一个Fruit,这个Fruit可以是Orange等其他类型的Fruit。
*/
public class GenericWriting {
private List<Apple> apples = new ArrayList<Apple>();
private List<Orange> oranges = new ArrayList<Orange>();
private List<Fruit> fruit = new ArrayList<Fruit>();
<T> void writeExact(List<T> list, T item) {
list.add(item); //TODO :这里是 add
}
// ? super T
// T 及 T 的父类
<T> void writeWithWildcard(List<? super T> list, T item) {
list.add(item);
}
void func1(){
writeExact(apples,new Apple());
writeExact(fruit,new Apple());
}
void func2(){
writeWithWildcard(apples, new Apple());
writeWithWildcard(fruit, new Apple());
}
@Test
public void test(){
func1();
func2();
}
}
JDK 8 Collections.copy() 源码:
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
//dest 就是 只写的 List
//src 就是 只读的 List
int srcSize = src.size();
if (srcSize > dest.size())
throw new IndexOutOfBoundsException("Source does not fit in dest");
if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) {
for (int i=0; i<srcSize; i++)
dest.set(i, src.get(i));
} else {
ListIterator<? super T> di=dest.listIterator();
ListIterator<? extends T> si=src.listIterator();
for (int i=0; i<srcSize; i++) {
di.next();
di.set(si.next());
}
}
}