Java与Kotlin中的泛型之:擦除、不变、协变、逆变

Java与Kotlin中的泛型之:擦除、不变、协变、逆变

前言

  • 对于Java中泛型的使用方法和应用场景等,不在本文章中作讨论,在阅读此篇文章时,我已经默认你对Java泛型有了一个较为清楚的认识和较为熟悉的应用熟练度。
  • 代码中的部分声明因篇幅原因没办法完全展示,只展示关键代码,但是别担心,你一定能看懂。
  • 本文章的内容均参考《Kotlin核心编程》中对该知识点的讲述,以及结合本人的实际开发经验。

概述

Java中的泛型(Generics)是Java 5中引入的一个特性,它提供了一种编译时类型安全检测机制,该机制允许程序员在类、接口、方法中使用类型参数(type parameters)。这样,类、接口和方法就可以操作多种类型的数据,而不是在编译时就已经确定下来的某一种类型。泛型的使用极大地增强了Java代码的复用性、灵活性和安全性。

尤其是JDK源码中在Java集合框架中大量使用到泛型,例如我们较为常用的List接口声明:

public interface List<E> extends Collection<E>

一道Java面试题

请问:以下输出结果是什么?

List<String> list1 = new ArrayList<String>();
List<Integer> list2 = new ArrayList<Integer>();
System.out.println(list1.getClass() == list2.getClass());

你可能会认为:List<String>List<Integer>很明显不是同一个类型,一定是返回false

但运行之后你会发现,返回结果为:true

在这其中作妖的就是接下来要说的:泛型的类型擦除

泛型的背后:类型擦除(Type Erasure)

概念

类型擦除是指:通过一些技术手段去掉(或”擦除“)编程语言中的类型信息,使得在运行时不再依赖于这些类型信息。这通常涉及到在编译器对类型信息进行替换处理,以便在运行时能够以一种统一的方式处理不同类型的对象。

简单来说就是:编译器会对类型进行擦除掩盖,使得程序在运行时无法得知泛型具体的类型信息。

Java中的Array与List

思考一个问题,你是否在Java中写过如下代码:

Array<SomeType>  array = new Array<>();

可能你会疑惑,数组的定义不是以下这种形式吗:

SomeType[] array = new SomeType[10];

是的,我们无法像定义一个List一样,使用泛型定义Array中的类型,这涉及到一个关键点:

Java无法声明一个泛型数组。

Java为什么无法声明一个泛型数组?

在解释这个问题之前,我们先来看一下Java对于泛型的实现方式

Dog[] dogArray = new Dog[10];
List<Dog> dogList = new ArrayList<>();

System.out.println(dogArray.getClass());
System.out.println(dogList.getClass());

// 运行结果
class [LDog;
class java.util.ArrayList

从上面的运行结果我们可以得知,Java中的Array在运行时是可以获取到自身类型的,而List<Dog>在运行时只知道自己是一个List,而无法获取泛型参数的类型。

这个现象与Java底层对泛型的实现有关:Java为了向后兼容所作出的牺牲。这需要在原本不支持泛型的基础上,以不改变老版本代码为目的,在新版本中以一种比较别扭的方式实现泛型———类型擦除

因此我们可以下一个结论:Java中的泛

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值