JAVA之泛型

泛型的一般表达

ArrayList<String> files = new ArrayList<>();

public class Classname<T> //T:类型参数

定义一个带有参数类型的简单方法:

class ArrayAlg

{    

       public static <T> T getMiddle(T....a)

       {

                 return .......;

        }

}

注意:类型修饰符放在修饰符后面,返回类型前面。

调用这个方法的语句:

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

类型变量的限定:public static <T extends ClassName> T Func(ArguType ......argu);

一个类型或通配符可以有多个限定,用&分开。

public class Pair<T>

{ private Object first;

private Object second;

public Pair(Object first,Object second)

{ this.first = first;

this.second = second;}

public Object getFirst(){return first;}

public Object getSecond(){return second;}

public void setFirst(Object newValue) {first = newValue;}

public void secSecond(Object newValue) {second = newValue;}

}

 

泛型代码和虚拟机

虚拟机没有泛型类型对象——所有对象都属于普通类。

类型擦除

擦除类型变量,并替换为限定类型,原始类型用第一个限定的类型变量来替换,无限定类型的变量就用Object替换。

当extends后有多个限定变量时,应该把标签接口放在尾部。标签接口:没有方法的接口。

翻译泛型表达式

 当程序调用泛型表达式,如果擦除返回类型,编译器插入强制类型转换。

例如:Pair<Employee> buddies = Pair(first,second);//这里的first和second必须是<>内的限定类型。即first = new Employee(...);

Employee body = buddies.getfirst();编译器把这个方法调用翻译为两条虚拟机指令:

1.对原始方法Pair.getFirst()的调用。

2.将返回的Object类型转换为Employee;

存取泛型域的时候也要插入强制类型转换,例如:Employee buddy = buddies.first;

翻译泛型方法:需要记住桥方法

个人理解:多态与擦除出现冲突,可以理解为子类重载了父类的一个方法,导致最后虚拟机不知道应该调用哪个方法(比如说,Employee 对象可以当作Object对象),然后使用合成桥方法类解决这个问题。(合成桥方法是虚拟机内部的机制,是由虚拟机自动完成的。)桥方法会使用父类的那个函数来调用子类的函数。

泛型的约束与局限性

不能用基本类型实例化类型参数。

例:Pair<double> 语法错误,只能用Pair<Double> (装箱)

运行时类型查询只适用于原始类型

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

如果要收集参数化类型对象,只有一个安全而有效的方法:ArrayList<Pair<ClassName>>

Varargs警告

@safeVarargs

public static <T> void addAll(Collection<T>,T...ts)

这时可以提供泛型类型来调用这个方法。

不能实例化类型变量

new T[...],new T(....),T.class等都是错误的,因为T会擦除为Object。

不能构造泛型数组

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

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

甚至连泛型类扩展Throwable都不合法。例:public class Problem<T> extends Exception {.......}//ERROR

catch子句不能使用类型变量。即catch(T e)//ERROR

public static <T extends Throwable> void doWork(T t) throws T//OK

可以消除对受查异常的检查

注意擦除后的冲突

要想支持擦除的转换,就要强行限制一个类或类型变量不能同时成为两个接口类的子类,而这两个接口是同一接口的不同参数化。例:

class Employee implements Comparable<Employee> {......};

class Manager extends Employee implements Comparable<Manager>;

是不合法的,因为对于Manager对象来说,compareTo()方法有两个可以调用。

泛型的继承

无论S与T有什么关系,一般情况,Pair<T>,Pair<S>都不会有什么关系。泛型的继承和普通的继承基本相同,extends语句。

通配符类型

Pair<? extends ClassName> 表示任何泛型Pair类型,它的类型参数是ClassName的子类。//可以使用访问器,无法使用构造器.

Pair<? super ClassName> 表示类型参数是ClassName的所有超类型。//可以使用构造器,不能使用访问器。

带有超类型限定的通配符可以向泛型对象写入,带有子类限定的通配符可以从泛型对象中读取。

主要原因是:父类可以引用子类,但是子类不能引用父类。

无限定通配符 Pair<?>.类型Pair<?>有以下方法: ? getFirst(); void setFirst(?);

getFirst()的返回值只能赋给Object对象。setFirst不能被调用,甚至不能被Object调用。Pair<?>和Pair本质的不同在于:可以用任意Object对象调用原始Pair类的setFirst方法。注释:可以调用setFirst(null).例:

public static boolean hasNulls(Pair<?> p)

{return p.getFirst() == null || p.getSecond == null;}

注:引用子类的父类在调用之内与自己相同的方法时,使用的是自己的方法(前提是没有进行类型转换)。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值