【Java】泛型

总结几个泛型中的典型问题。

 

1.泛型作用

Java在1.5中引入了泛型的概念,为什么要引入?解决什么样的问题?

泛型主要用在“编写与类型无关的类”的场景中。比方说,我想写一个容器类,可以放Integer,可以放String,可以放任意类型。是不是针对每一种类型都要实现一套容器?这样很显然不合理,因为关于容器部分的代码都是一样的,区别就是类型不同而已。所以,目的是只写一套代码,支持不同的类型。不过,想完成这个目标,不用泛型也行,在1.5之前就是用Object来实现的。只不过用Object会有一些问题。比如:

1)使用不便;取元素时,必须加一次向下的强转;

2)类型不安全;向下强转有风险的,因为放的时候,可以放入任何类型的元素。并且,类型转换的问题只能在运行时暴露;

泛型将类型变为了一个参数,在使用泛型类时,一般需要指定参数类型(除非使用通配符),这样,在调用泛型的api时,编译器就能提供一层静态的检查,从而在编译期就能保证泛型类型是正确的。在取值时,自然可以安全地强转。

 

2.泛型的实现

Java中泛型的实现机制是类型擦除。

也就是说,泛型的概念 仅仅存在于编译期,被编译后的代码是没有泛型的概念的,泛型的类型参数都被替换为了上届类型,如果不指定,默认就是Object。取值的操作,编译期会自动加上一次强转。

 

3.为什么使用擦除实现泛型?

Java泛型的实现和C++等语言不同,仅仅是一种存在于编译期的机制。为什么采用这种方式?《Java编程思想》里这么解释:泛型擦除可以保证Java语言不同版本的兼容性。

因为最开始设计Java语言的时候,并没有考虑到泛型这种问题。直到1.5才引入泛型,如何保证新老代码能够兼容是一个很重要的问题,最终Java设计者们才使用了类型擦除这种技术实现泛型,看上去是一种折中。

这个兼容怎么理解?

比如说我现在的代码是使用老版本的java语言写的,我的代码以及jvm根本不认识泛型是什么。但是,我用的一个类库却是使用泛型来编写的,由于编译后的泛型代码已经类型擦除了,所以在运行时,新代码的class文件照样可以运行在老的jvm上,这就是类型擦除保证兼容的原因。

但如果采用了类似C++模板的实现机制,将泛型类型保留在运行时,显然,老的jvm就无法支持新代码运行了,这就导致兼容性问题的出现。

 

4.泛型协变

https://blog.csdn.net/u010900754/article/details/101113667

 

5.通配符

 泛型不允许协变,所以泛型变量之前不具备任何父子关系,但是,我们又是确实需要这种父子关系做一定的抽象编程,这在框架代码或者是通用逻辑里面非常常见,举个简单的例子:

    public void print(List<Integer> list) {
        for(int i : list) {
            System.out.println(i);
        }
    }

我就是想实现一个打印List的通用方法,但是因为List不能协变,难道要为所有的类型T,都提供List<T>的print方法吗?这显然不是好的做法。

为了解决泛型的抽象,泛型提供了通配符。

简而言之,通配符可以理解为阉割版本的泛型协变。就是说,通配符允许泛型抽象(父子关系),但是不会完全提供这种能力,是会有一定的限制的。

具体来说,可以使用两种通配符,每一种只能读或者写,二选一,不能兼备。

extends:

比如说List<? extends Number> list,这里申明了一个带有extends Number限定的泛型变量list,什么含义?

含义是,这个list可以接受任何List<T>变量的赋值,其中T必须是Number的子类型。

这是不是有点类似协变了,算是一种抽象。

但是,有一个限定,这个list变量只能get,不能add。

    public static void read(List<? extends Number> list){
        list.add(1);
    }

这里的list.add(1),会编译报错。

但是这样就没问题了:

    public void print(List<? extends Number> list) {
        for(int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }

为什么extends只能读取不能写入呢?

想想前面提到的extends Number的含义:“这个list可以接受任何List<T>变量的赋值,其中T必须是Number的子类型”。

说明,list里的元素可以保证都是Number类型的,当然具体是什么样的子类型不知道,但是,我把里面的元素当做Number来使用(get)是没有任何问题的。这个是编译期保证的。

所以extends的泛型变量只能读取。

 

super:

比如说List<? super Number> list,这里申明了一个带有super Number限定的泛型变量list,又是什么含义?

含义是,这个list可以接受任何List<T>变量的赋值,其中T必须是Number的父类型。

这样,可以保证list变量里的元素一定是Number的父类型。如果是这样,那么就不能把list里的元素当做Number来处理的,所以不能get。但是,可以往里面添加Number类型的元素,因为,被赋值的list的类型一定是Number的父类型,所以往里面添加Number类型的元素肯定没有问题。但是如果非要读取,也只能按照被赋值的父类型来读取了。

例子:

    public static void write(List<? super Number> list, Number number){
        list.add(number);
    }

这个write函数是没有任何问题的。

这样定义的print和write就是使用通配符定义的比较抽象的泛型函数了。

 

完整的例子:

        List<Integer> list = new ArrayList<>();
        list.add(1);
        print(list);

        List<Object> list2 = new ArrayList<Object>();
        write(list2, 999);
        System.out.println(list2.get(0));

 

6.泛型桥方法

https://blog.csdn.net/u010900754/article/details/81780238

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值