泛型

泛型:被不同类型的对象所重用

用继承(objec)实现的两个问题:

1 获取一个值时必须强制进行类型转换

2 可以向数组列表中添加任何类的对象

类型参数:(可读性、安全性)

定义简单泛型类:

public class Pari<T>{}

public class Pair<T,U>{}

public class HashMap<K,V>{}

使用泛型类:

ArrayList<String> files = new ArryList<String>()(两边必须相同)

ArrayList<String> files = new ArryList()

ArrayList files = new ArryList<String>()

使用一个泛型类时,只要在后面加上<具体的类型>

定义泛型方法(可以在普通类及泛型类中定义):

class ArrayAlg{

 public static <T> T getMiddle(T...a){  //注意类型变量的位置

     return a[a.length/2]

  }

}

泛型方法的调用:

String middle=ArrayAlg.<String>getMiddle("bb","cc","dd")

String middle=ArrayAlg.getMiddle("bb","cc","dd")

类型变量的限定:<T extends BoundingType>这里的T和BoundingType既可以是类也可以是接口,使用extends更加表现出子类的概念

 <T extends BoundingTypeA & BoundingTypeB>可以多个超接口,最多一个类(必须第一个)

静态方法不能使用类定义的泛形,而应单独定义泛形。 泛形的典型应用:BaseDao和反射泛型

泛型与虚拟机:

虚拟机没有泛型类型对象

泛型代码与虚拟机:

自动提供原始类型,擦除类型变量,替换为限定类型(无则用object)

当调用泛型方法时,编译器对返回的object进行强制类型转换

泛型类擦除造成原本在泛型类子类中覆盖的方法变成了重载。(参数类型变成了object)导致子类出现了同一方法名两种参数的方法,调用时本来只希望调用子类的方法(多态),结果有可能调用了泛型超类中的参数为objec的方法。编译器自动在子类中加入桥方法:

public void setSecond(object a){setSecond((Date) a)}

同样在有返回类型的方法中,也会产生两个相同参数类型的方法。虚拟机根据参数类型和返回类型确定一个方法。

一个方法覆盖另一个方法时可以指定一个更加严格的返回类型。

1 虚拟机中没有泛型,只有普通类和方法;2 所有类型参数都用他们的限定类型替换 3 桥方法保持多态 4为保持安全性,必要时插入强制类型转换  

允许泛型代码和遗留代码之间能够互操作。

泛型的约束与局限(大多由擦除引起):

1.不能用基本类型实例化类型参数,objec不能储存double的值。

2.运行时的类型查询只适用于原始类型。使用instanceof,getcalss或泛型类型的强制转化时,都是类型擦除后的效果。

3.不能创建参数化类型的数组:Pair<String>[] table=new Pair<String>[10]//error,擦除机制将会导致table数组中可以插入任意的Pair<otherclass>

4.Varargs警告,向参数可变的方法传递一个泛型类型的实例。由于个数可变参数实际上是一个数组,所以会违反第三条,但是只会得到一条警告。

5.不能实例化类型变量:(如果想通过T来构造对象)

new T(),T.class//both error

public Pair(){first=new T();second=new T();}//error

saddly,由于不能调用T.class:

 first=T.class.newInstance()也是错误的

如果非要通过反射调用Class.newInstance来构造泛型对象:在Pair中新建一个泛型方法,由于Class本身是泛型,String.class是Class<String>的一个实例



public
static <T> Pair<T> makePair(Class<T> cl){ try{return new Pair<>(cl.newInstance(), cl.newInstance()) ;} catch(Exception ex){return null;} }
调用:
Pair<String> p = Pair.makePair(string.class);

 不能构造一个类型变量的数组:

public static <T> T[] minmax(T[] a){T[] mm = new T[2];....}//error

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

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

泛型类cannot extend throwable;不能catch类型变量(声明中可以throws类型变量)

。。。。

泛型类型的继承规则:

Pair<employee>和Pair<manager>之间没有关系

Pair<employee> b=Pair<manager> a //error

假设可以转换,则会出现可以在b中存储低级别雇员(由于没有保护)

注意数组和泛型的区别,如果一个manager[]数组赋值给employee[]变量a,则这个变量会带有特别的保护,即低级别雇员无法存储到a[0]。

Pair<Employee>时原始类型Pair的一个子类型

泛型类可以扩展或实现其他的泛型类。如ArrayList<T>实现了List<T>接口。

通配符类型:

public static void printBuddies(Pair<employee> p){....}

由于Pair<employee>Pair<manager>之间没有关系,所以上述方法中不能传入Pair<manager>

引入通配符:public static void printBuddies(Pair<extends employee> p){....}

Pair<manager>Pair<extends employee>的子类型

原文地址:https://www.cnblogs.com/ChuPengcheng/p/5895343.html