对泛型的理解

概述:

集合中是可以存放任意对象的,只要把对象丢进集合后,那么这时他们都会被提升成Object类型。当我们在取出每一个对象,并且进行相应的操作,这时必须采用类型转换。

举例:

  public static void main ( String[] args ) {
        ArrayList list = new ArrayList();
        list.add("abc");
        list.add("itcast");
        list.add(5);     //由于集合没有做任何限定,任何类型都可以给其中存放
        Iterator it = list.iterator();
        while (it.hasNext()) {        //需要打印每个字符串的长度,就要把迭代出来的对象转成String类型
            String str = (String) it.next();
            System.out.println(str);
        }
    }
}

则会出现以下情况:

abc
itcast
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at Day13.Demo02.main(Demo02.java:22)

Process finished with exit code 1

程序在运行时发生了java.lang.ClassCastException

类型转化异常:

由于集合中什么类型的元素都可以存储。导致取出时,如果出现强转就会引发运行时ClassCastException异常。
我们知道在前面学习数组时,只要数组定义好,那么这时给数组中存放的数据类型就确定,这时如果给数组中存放的数据类型和数组类型不一致,编译时就会报错。
JDK1.5以后,出现了解决方案,使用容器时,必须明确容器中元素的类型。这种机制称之为 :泛型。

泛型格式:

<数据类型>,这种格式不是很难理解,<>尖括号也是括号,往括号里面写东西其实就是在传递参数。

泛型这种机制的好处:

1,安全机制。

2,将运行时期的ClassCastException,转移到了编译时期变成了编译失败。

3,泛型技术,是给编译器使用的技术。

4,避免了强转的麻烦。

public static void main ( String[] args ) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("abc");
        list.add("itcast");
        list.add("5");     //由于集合没有做任何限定,任何类型都可以给其中存放
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {        //需要打印每个字符串的长度,就要把迭代出来的对象转成String类型
            String str =  it.next();
            System.out.println(str);
        }
    }
}

结果如下:

abc
itcast
5

Process finished with exit code 0

泛型通配符

无法确定具体集合中的元素类型是什么,就可以使用泛型的通配符机制来完成。

当使用泛型类或者接口时,传递的具体的类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符机制后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。通常这样来写:List<?>list。

泛型限定

想要对被打印的集合中的元素类型进行限制,只在指定的一些类型,进行打印。怎么做呢?要解决这个问题,我们就要学习泛型限定

对泛型界限的理解

我们定义一个Box,现在我们想象里面可以装水果那我们就可以这样写

Box<Fruit>  box=Box<Apple>(new Apple)

不过这样的写是不行的,编译器会报错所以就会有

限定泛型的上限:? extends E:接收E类型或者E的子类型。当然有上限,
肯定也有泛型的下限:? super E:接收E类型或者E的父类型。

现在我们把上面的 Box 定义改成:
Box<? extends Fruit>
这就是上界通配符, 这样 Box 及它的子类如 Box 就可以赋值了。
Box<? extends Fruit> box = new Box<Apple>(new Apple)

其中蓝色代表Box<? extends Fruit> box

上界代表只能取树的叶子,只能取外围不能往里放

<? super Fruit>上界通配符对应黄色区域

表示想要放这个水果必须有盒子能实现水果的基类,也就是意思说要实现多态。能放食物的盒子可以去放水果,放水果的盒子重写了食物的放的内容。

也就是所在叶子的必须有一个根,叶子就是你想去实现的内容。

使用场景

在使用泛型的时候可以遵循一些基本的原则,从而避免一些常见的问题。

在代码中避免泛型类和原始类型的混用。比如List和List不应该共同使用。这样会产生一些编译器警告和潜在的运行时异常。当需要利用JDK 5之前开发的遗留代码,而不得不这么做时,也尽可能的隔离相关的代码。

在使用带通配符的泛型类的时候,需要明确通配符所代表的一组类型的概念。由于具体的类型是未知的,很多操作是不允许的。

泛型类最好不要同数组一块使用。你只能创建new List<?>[10]这样的数组,无法创建new List[10]这样的。这限制了数组的使用能力,而且会带来很多费解的问题。因此,当需要类似数组的功能时候,使用集合类即可。

不要忽视编译器给出的警告信息。

PECS 原则

如果要从集合中读取类型T的数据, 并且不能写入,可以使用 上界通配符(<?extends>)—Producer Extends。

如果要从集合中写入类型T 的数据, 并且不需要读取,可以使用下界通配符(<? super>)—Consumer Super。

如果既要存又要取, 那么就要使用任何通配符。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值