Java泛型

17 篇文章 1 订阅
15 篇文章 0 订阅
"Java泛型是一种参数化类型,允许在编译时进行类型检查,提高代码安全性。类型擦除是Java泛型的特性,编译后泛型信息被替换为原始类型,但通过类型检查保证了类型安全。泛型中E、T、K、V等是类型参数的常见别名,?代表不确定的类型,限定通配符如"? extends T"和"? super T"则限制了类型范围。理解这些概念能更好地掌握Java泛型的使用。"
摘要由CSDN通过智能技术生成

Java泛型

一、概述

泛型程序设计是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。

  • 在程序编码中一些包含类型参数的类型,也就是说泛型的参数只可以代表类,不能代表个别对象。
  • 在程序编码中一些包含参数的类。其参数可以代表类或对象等等。

不管是类还是参数,泛型的参数在真正使用泛型时都必须作出指明。

Java泛型是J2 SE1.5中引入的一个新特性,其本质是参数化类型,也就是说所操作的数据类型被指定为一个参数(type parameter)这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

但他并没有完全真正的实现泛型,而是通过一些内部处理来使其看起来像泛型,这也是为什么有人称之为伪泛型的原因。

二、类型擦除

如果研究过其他泛型程序设计语言(如:C#、.NET),会发现Java泛型只体现在源码层面,在编译后的字节码文件中,就被替换成了原始类型。并且在相应的地方加以转换处理,因此对于运行时的Java来说ArrayList<String>ArrayList<Integer>是同一个类。这实际就是是一种语法糖,而非真正实现泛型。

在编译期间将所有泛型信息(类型变量、参数化类型)替换为原始类型的过程就是类型擦除。

public static void main(String[] args) {

        ArrayList<String> list1 = new ArrayList<>();
        list1.add("abc");

        ArrayList<Integer> list2 = new ArrayList<>();
        list2.add(123);
		
        System.out.println(list1.getClass() == list2.getClass());
  }

这段代码最终会输出true,两个不同泛型类型的对象的类(字节码)是一样的。说明泛型类型StringInteger都被擦除掉了,只剩下原始类型。

2.1、类型擦除带来的问题以及解决方法

使用类型擦除的方式会导致与原来的语言设计上出现一些问题,当然Java设计者已经在里面进行了处理。

2.1.1、在类型擦除后如何保证只能使用泛型变量限定的类型呢?

public static void main(String[] args) {

         ArrayList<Integer> list1 = new ArrayList<>();
         list1.add(123);
    	 list1.add("123");	//编译异常
    	 ArrayList list2 = new ArrayList<Integer>();
    	 list1.add(123);
    	 list1.add("123");	//编译正常
  }

如上,类型擦除后,类型应该是原始类型Object了,也就是说可操作任何Java类型,但显然并不行,它只能操作泛型变量限定的类型的元素。

这就是设计者的解决方法:类型检查
在编译前,先进行类型检查,new ArrayList<>只是开辟一个内存空间,可以存储任何类型的数据对象,而类型检查是针对它的引用,这个引用list1调用泛型方法时,就会进行类型检查,而无关于它真正引用的对象new ArrayList<Integer>()

2.1.2、自动类型转换

经过类型擦除后,字节码没有了任何泛型类型的信息,类型都是Object,那么在后续存取时是否需要通过强转才能获得泛型类型的数据呢?

//ArrayList.get(int index);
   E elementData(int index) {
        return (E) elementData[index];
    }

    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

对此,设计者也在里面进行转换,而不需要开发者每次都做转换操作。

类型擦除还有很多类似的问题,而设计者也对应的进行了处理,有兴趣的可深入了解:类型擦除后与多态的冲突、在静态方法\类的问题、运行时类型查询等问题。

三、泛型中E、T、K、V、N、?、Object等通配符的含义

  • E: Element (在集合中使用,因为集合中存放的是元素)

  • T: Type(Java 类型)

  • K: Key(键)

  • V: Value(值)

  • N: Number(数值类型)【Short、Integer、Float、Double、Number、Long…】

  • ?: 不确定的java类型(非限定通配符)

  • Object: 所有类的根类,任何类型的对象都可以设置给改Object引用变量,使用的时候可能需要进行类型转换

四、限定通配符和非限定通配符

限定通配符就是对泛型类型进行了限制,而限定通配符可以限定泛型类型的上界与下界:

  • 限定上界:<? extends T> 表示泛型类型必须是T类型或者是T的子类
  • 限定下界:<? super T> 表示泛型类型必须是T类型或者是T的父类

如果泛型类型在限定界限外将会导致编译时错误。

非限定通配符<?> 表示泛型类型可以是任何类型。

五、List<Object>和原始类型List以及List<?>之间的区别

ListList<Objec>List<?>
类型原始类型实际类型参数为Object的参数化类型通配符类型
泛型类型任何对应List<E>的参数化类型仅接受List和其本身类型任何对应List<E>的参数化类型,包括List
元素类型可以操作任意类型的元素可以添加任何元素不能添加任何元素
安全性不安全安全性安全性
便利性不便利性便利性不便利性
表述性不表述性表述性表述性
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值