分类:
泛型类
泛型接口
泛型方法
泛型类:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
public E get(int index) {
rangeCheck(index);
checkForComodification();
return ArrayList.this.elementData(offset + index);
}
//...省略掉其他具体的定义过程
}
泛型接口:
public interface List<E> extends Collection<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean addAll(int index, Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
boolean equals(Object o);
int hashCode();
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
List<E> subList(int fromIndex, int toIndex);
}
泛型方法:
在调用方法的时候,已经指明泛型方法的具体类型
public <T> T showKeyName(Generic<T> container){
System.out.println("container key :" + container.getKey());
//当然这个例子举的不太合适,只是为了说明泛型方法的特性。
T test = container.getKey();
return test;
}
这才是一个泛型方法,首先在public与返回值之间必不可少,表明这是一个泛型方法,并且声明了泛型T,这个T可以出现在泛型方法的任意位置
泛型的引用 可以 把使用Object的错误提前到编译后,而不是运行后,提升安全性
类型擦除:
Java虚拟机中不存在泛型,泛型只是为了完善Java体系,增加程序员编程的便捷性以及安全性而创建的一种机制,在Java虚拟机中对应的泛型都是确定的类型。
Java虚拟机会把这些泛型参数类型都擦除,用相应的确定类型来代替,这个动作叫做类型擦除,用于代替的类型成为原始类型,在类型擦除过程中,一般使用第一个限定的类型来替换,若无限定则使用Object。
class Test<T>
{
private T t;
public void show(T t)
{
}
}
虚拟机进行翻译后的原始类型
class Test
{
private Object t;
public void show(Object t)
{
}
}
泛型类(带限定类型)代码:
class Test<? extends Comparable>
{
private T t;
public void show(T t)
{
}
}
虚拟机进行翻译后的原始类型:
class Test
{
private Comparable t;
public void show(Comparable t)
{
}
}
泛型类的翻译
class Test<T>
{
private T t;
public void show(T t)
{
}
}
class TestDemo extends Test<String>
{
private String t;
public void show(String t)
{
}
}
如果泛型类型的类型变量没有限定,那么就用Object作为原始类型
如果有限定()就用XClass作为原始类型
如果有多个限定(<T extends XClass1&XClass2>)就用第一个边界的限定类型XCLass1类作为原始类型。
由于TestDemo继承了Test,但是Test在类型参数后还有一个public void show(Object t),这和那个show(String t)出现重载,但是本意确实没有show(Object t)的
因此在虚拟机翻译泛型方法中,引入了桥方法,及在类型擦除后的show(Object t)中调用另一个方法,从而达到子类覆盖父类的方法,这种操作只有JVM才可以实现
public void show(Object t)
{
show((String) t);
}
类型限定
? extends SomeClass 这种限定,说明的是只能接收SomeClass及其子类类型,所谓的“上限”
? super SomeClass 这种限定,说明只能接收SomeClass及其父类类型,所谓的“下限”
public <T extends Comparable> shwo(T a, T b)
{
int num = a.compareTo(b);
}
也可以有多重类型限定
<T extends Comparable & Serializable>
多种类型限定类型擦除机制
class Test<T extends Comparable & Serializable>
{
private T lower;
private T upper;
public Test(T first, T second) //此处是利用Comparable的方法,因此把Comparable写在前边,类型擦除后为Comparable,若为Serializable,还得用强制类型转换,否则不能使用compareTo方法。
{
int a = first.compareTo(second);
...
}
}
泛型误区:
泛型的类型必须是类的引用,不能是基本数据类型
不能创建参数化类型数组
不能实例化类型变量,以及不能出下泛型调用信息
T t = new T();
//或
T.Class
不能再静态域 or 方法中出现参数类型,但是可以使用静态泛型方法
class Test<T>
{
private static T example; //error 执行泛型静态变量
public static void showExample() //error 在静态域中操作不能类型擦除的泛型
{
action about T...
}
public static T showExample() //error 静态泛型返回值
{
action about T....
}
}
//非泛型方法,和在静态方法中使用费静态参数是一样的,静态方法是先于对象而存在于内存中的,因此在编译的时候,T的类型无法确定,会抛出:
“Cannot make a static reference to a non_static reference”
//静态泛型方法是对的
class Test<T>{
public static <T> T show() {
action
}
}
不能抛出or捕获泛型类的实例
try
{
....
}
catch(T e) //error
{
...
}
在异常规范中使用使用类型变量是允许的,一下方法是合法的:
public static<T extends throwable> void doWork(T t) throw T //ok
{
try{
do work;
}catch(Throwable realCause){
log;
}
}
泛型类型中的方法冲突
由于类型擦除
public class Pair<T>{
public boolean equals(T value){
return (first.equals(value));
}
}
在类型擦书后与Object中额equals方法方法签名一样
出现Error
【Error】 Name clash: The method equals(T) of type Pair<T> has the same erasure as equals(Object) of type Object but does not override it