java 泛型 捕获转换_java 泛型 窜讲

一、为什么使用泛型

复用性:泛型的本质就是参数化类型,因而使用编写的泛型代码可以被许多不同类型的对象所复用。

安全性:在对类型Object引用的参数操作时,往往需要进行显式的强制类型转换。这种强制类型转换需要在运行时才能被发现是否转换异常,通过引入泛型能将在运行时才能检查类型转换,提前到编译时期就能检查。

二、自定义泛型

java中自定义泛型分为三种:泛型类、泛型接口、泛型方法。

下面使用一个案例演示泛型类、泛型方法,泛型接口类似,所以不再演示。

// 自定义泛型类

public class Generic

{

private T second;

public void setSecond(T newValue)

{

second = newValue;

}

// 自定义泛型方法

public static void printValue(W obj)

{

System.out.println(obj.toString());

}

@Override

public String toString()

{

return second.toString();

}

public static void main(String[] args)

{

//

Generic g = new Generic();

g.setSecond("zhang");

System.out.println(g);

// 使用泛型方法

Generic.printValue(45);

Generic.printValue("hello");

}

}

泛型方法可以在普遍类中定义,也可以在泛型类中定义。

三、java泛型的特性

1、擦除

java中的泛型是伪泛型,因为在编译期间,所有的泛型信息都会被擦除,而只保留原始类型。比如,代码List和List在经过编译后,都会变成List类型。

为什么会出现这种情况呢?这跟java的虚拟机有莫大的关系。java虚拟机没有泛型类型对象-----所有对象都属于普通类。由于在java1.5之前没有泛型,那之前没有泛型的代码怎么与有泛型的代码共存了,为了兼容性,java虚拟机采用统一的普通类。

下面使用代码,体现类型擦除。

public static void main(String[] args)

{

ArrayList arrayList1=new ArrayList();

arrayList1.add("abc");

ArrayList arrayList2=new ArrayList();

arrayList2.add(666.666);

System.out.println(arrayList1.getClass()==arrayList2.getClass());

}

输出结果:

true

2、补偿

public static void main(String[] args)

{

ArrayList arrayList1=new ArrayList();

arrayList1.add("abc");

String str = arrayList1.get(0);    // 编译正常

int str2 = arrayList1.get(0);      // 编译报错

}

arrayList1.get(0);

编译过后,泛型会被擦除,arrayList1.get(0)返回Object类型。但是由于java的补偿机制,因此编译器会自动的插入String的强制类型转换。由于int类型的str2不能接收经过强制转换的String类型,因而编译报错。

四、java泛型的约束

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

比如:错误-->Arraylist; 正确-->Arraylist

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

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

4、不能实例化类型变量

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

比如:private static T single; // ERROR

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

五、通配符类型

1、限定上界通配符

比如:List extends Animal>,表示任何泛型List类型,它的类型参数是Animal类及子类,List、List、List都是List extends Animal>子类型。

public static void main(String[] args)

{

List extends Animate> animates = new ArrayList();         // OK

List extends Animate> animates1 = new ArrayList();            // OK

List animates2 = new ArrayList();                  // OK

List animates3 = new ArrayList();                      // compile-time error

}

其实,我们可以将List extends Animate> animates 看做是List、List等的集合。

归纳:假如给定的泛型类型为G,两个具体的泛型参数X、Y,当Y是X的子类时(Y extends X)

G extends Y> 是 G extends X>的子类型(如List extends Cat> 是 List extends Animal>的子类型)。

G 是 G extends X>的子类型(如List 是 List extends Animal>的子类型)

G> 与 G extends Object>等同,如List> 与List extends Objext>等同

学到这里,可能会遇到一些疑惑的地方,或者说事理解不透的地方,先观察如下两段代码片段,判断一下其是否可行??

List extends Animal> animal = new ArrayList<>();

animal.add(new Animal());

animal.add(new Cat());

上面的两个add操作都不能通过编译。为什么呢?由于List:add(E e)加入泛型变成List extends Animal>:add(? extends Animal e),? extends Animal参数类型无法确定,可以是Animal、Cat等,所以为了保护其类型的一致性,因此不允许向list对象中添加任意对象,除了null。

注意:上界限定一般用在:? extends T get()方法上(读数据操作)

2、限定下界通配符

比如:List super Cat>,这个通配符限制为Cat的所有超类型(包括本类)。

它的归纳方法与上界通配符相似,这里就不啰嗦了。

看下面代码:

List super Animate> animates = new ArrayList<>();

animates.add(new Animate());

animates.add(new Cat());

上述代码编译通过,编译器不知道add方法的确切类型,但是可以用任意Animal对象(或子类型对象)。

注意:下界通配符通常用于:set(? extends T>)方法上(写入数据操作)

3、无限定通配符

比如:List>,当类型不确定时,才使用,该通配符较少使用。

关于上下界限定通配符,建议参考:《编写高质量代码:改善java程序的151个建议》中建议96:不同的场景使用不同的泛型通配符

参考

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值