Java提升(泛型)

java泛型

本质 参数化类型

好处 安全 简单

T代表type E代表element

T 一般用在标识类型 比如 Class< T > clazz 或者 T extends Serializable

E一般是标识集合类型中的元素的类型 是一种命名习惯 比如

public interface List< E > extends Collection< E >

Iterator是迭代器类,而Iterable是接口 好多类都实现了Iterable接口,这样对象就可以调用iterator()方法 一般都是结合着用,比如

HashMap类就实现了Iterable接口,而要访问或打印出Map中所有内容时,就可以这样:

HashMap hashMap; Iterator iter = hashMap.iterator(); while(iter.hashNext()) { String s = iter.next(); }

为什么一定要实现Iterable接口,为什么不直接实现Iterator接口呢?

看一下JDK中的集合类,比如List一族或者Set一族,都是实现了Iterable接口,但并不直接实现Iterator接口因为Iterator接口的核心方法next()或者hasNext() 是依赖于迭代器的当前迭代位置的。

如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。但即使这样,Collection也只能同时存在一个当前迭代位置。

而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。多个迭代器是互不干扰的

Iterator是一个遍历器。它相当于一个游标,刚开始时指向要遍历的集合(比如程序中的String数组)的第一个元素之前,然后每调用一次next()方法,这个游标就会向前走一格,当走到集合最后一个元素之后,hasNext()方法会返回false,表示游标已经走到最后,没有下一个值了。

Iterator 接口定义如下

public interface Iterator<e> {

boolean hasNext();

E next();

void remove();

}

Iterable 接口定义如下

public interface Iterable<t> {

Iterator<t> iterator();

}

Set和List继承自Collections Map不是继承自Collection

Collections的功能(不包括从Object继承的)

boolean add(T) boolean addAll(Collection<? extends T>) void clear() boolean contains(T)

Boolean containsAll(Collections<?>) booleanisEmpty() Iterator<T> iterator() 返回一个iterator<T>

用来遍历容器中的所有元素

Boolean remove(Object)

boolean removeAll(Collection<?>)

Boolean retainAll(Collection<?>) 只保存参数中的元素

int size()

Object[] toArray() <T> 返回数组

T[] toArray(T[] a)

---------

generic

为什么不直接用个String数组? 我们不希望为String和其他对象分别设计不同的类

数组存在的问题 public Object get(int i){} 这样的实现有两个问题 当获取一个值的时候必须强制类型转换String filename = (String) files.get(0);

另外这里没有错误检测 可以向数组元素中添加任何类的对象files.add(new File("..."));

如果将get的结果强制类型转换为String类型 就会产生一个错误

泛型提供了类型参数(type parameters) ArrayList<String> files = new ArrayList<String>();

调用泛型方法的时候 在方法名的尖括号中放入具体的类型

String middle = ArrayAlg.<String>getMiddle("John", "Q", "Public");

也可以省略String middle = ArrayAlg.getMiddle("John", "Q", "Public");

class ArrayAlg { public static < T > T min ( T[] a ) { if ( a == null || a.length == 0 ) { return null; } T smallest = a[ 0 ]; for ( int i = 1 ; i < a.length ; i++ ) { if ( smallest.compareTo( a[ i ] ) > 0 ) { smallest = a[ i ]; } } return smallest; } }

这里有一个问题 怎么保证smallest有compareTo方法呢? 解决这个问题是将T限制为实现了Comparable

接口的类

public static <T extends Comparable> T min( T[] a){} 多个限定符用&分隔

T extends Comparable & Serializable

翻译泛型方法

public static <T extends Comparable> T min(T[] a){} 类型擦除为 public static Comparable min(Comparable[] a)

但是方法的擦除会带来两个复杂的问题

class DateInterval extends Pair< Date >
{ public void setSecond ( Date second ) { if ( second.compareTo( getFirst() ) >= 0 )) { super.getSecond( second ); } } }
这个类擦除之后变成
class DateInterval extends Pair { public void setSecond(Date second){...} }

但是还存在另外一个从Pair继承的SetSecond方法 即

public void setSecond(Object second)

//考虑下面的语句
DateInterval interval = new DateInterval(); Pair<Date> pair = interval; pair.setSecond(aDate);

希望对SetSecond的调用具有多态性 由于pair引用DateInterval对象 所以应该调用DateInterval.setSecond

问题在于类型擦除和多台发生了冲突 要解决这个问题 需要编译器在DateInterval类中生成一个桥方法(bridge method)

public void setSecond(Object second) { setSecond((Date) second); }

pair.setSecond(aDate) 变量pair已经被声明为类型Pair<Date> 这个类型只有一个简单的方法教setSecond

即setScond(Object) 虚拟机用pair引用的对象调用这个方法 这个对象是DateInterval类型的 因而会调用

DateInterval.setSecond(Object)方法 这个方法是合成的桥方法 它调用setSecond((Date) second); 这是我们所希望的

记住java泛型的事实

jvm中没有泛型 只有普通的类和方法 所有的类型参数都用它们的限定类型转换 桥方法被合成来保持多态  为保持类型安全性 必要时插入强制类型转换

1.不能用基本类型实例化类型参数 没有Pair<double> 只有Pair<Double>

2.运行时类型检查只适用于原始类型

Pair<String> stringPair = ...;

Pair<Employee> employeePair = ...;

stringPair.getClass() == employeePair.getClass();//true 返回的是Pair.class

3.不能创建参数化类型的数组

WRONG Pair<String>[] table = new Pair<String>[10];

4.不能实例化类型变量

5.泛型类的静态上下文中类型变量无效

6.不能抛出或捕获泛型类的实例

注意擦除后的冲突

public class Pair<T>

{ public boolean equals(T value){ return first.equals(value) && second.equals(value); }

考虑一个Pair<T> 从概念上将 它有两个equals方法

boolean equals (String) //define in Pair<T>

boolean equals (Object) //inherited form Object

List<? extends Fruit> flist = new ArrayList<Apple>();

//但是 不能添加任何对象 flist.add(new Apple());

Pair<Employee>和 Pair<Manger>并没有继承关系

Pair<? extends Employee>表示任何泛型Pair类型 它的类型参数是Employee的子类 如 Pair<Manager>

Pair<Employee>和 Pair<Manger>是Pair<? extends Employee>子类型

Pair<? super Manger>

Pair<? super Manger>是Pair<Employee>和Pair<Object>的基类

List<? super Apple> apples;

//可以向其中添加Apple或者Apple子类型的 如果可以添加Fruit 就可以添加 Banana等非Apple类型

无限定通配符 例如

Pair<?>? getFirst)(){}

void setFirst(?){}

直观的讲 带有超类型限定的通配符可以向泛型对象写入 带有子类型限定的通配符可以从泛型对象读取

Comparable接口本身也是一个泛型 声明如下

public interface Comparable<T>

{ public int compareTo(T other); }

由于Comparable 是一个泛型容器 可以把ArrayAlg的min方法做的更好一点 可以这么写

public static <T extends Comparable< ? super T>> T min(T[] a){} 这样写比T extends Comparable更彻底

有可能被声明为使用类型T 的对象 也有可能使用T的超类型 无论如何 传递一个T类型的对象给compareTo 都是安全的

你可能感兴趣的:(Java提升(泛型))