`

Java——协变数组和类型擦除(covariant array & type erasure)

 
阅读更多

1、数组的协变性

数组的协变性(covariant)是指:

如果类Base是类Sub的基类,那么Base[]就是Sub[]的基类。

而泛型是不可变的(invariant),List不会是List的基类,更不会是它的子类。


数组的协变性可能会导致一些错误,比如下面的代码:

1
2
3
4
public static void main(String[] args) {
    Object[] array = new String[10];
    array[0] = 10;
}

它是可以编译通过的,因为数组是协变的,Object[]类型的引用可以指向一个String[]类型的对象

但是运行的时候是会报出如下异常的:

1
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Integer


但是对于泛型就不会出现这种情况了:

1
2
3
4
public static void main(String[] args) {
    List< Object> list = new ArrayList< String>();
    list.add(10);
}

这段代码连编译都不能通过。

2、数组的具体化。

数组是具体化的(reified),而泛型在运行时是被擦除的(erasure)。

数组是在运行时才去判断数组元素的类型约束,

而泛型正好相反,在运行时,泛型的类型信息是会被擦除的,只有编译的时候才会对类型进行强化。

所以上面的例子中,数组的方法会在运行时报出ArrayStoreException,而泛型根本无法通过编译。

 

3、泛型不是协变的

 

虽然将集合看作是数组的抽象会有所帮助,但是数组还有一些集合不具备的特殊性质。

Java 语言中的数组是协变的(covariant),也就是说,如果 Integer扩展了 Number(事实也是如此),那么不仅 Integer是 Number,而且 Integer[]也是 Number[],在要求 Number[]的地方完全可以传递或者赋予 Integer[]。(更正式地说,如果 Number是 Integer的超类型,那么 Number[]也是 Integer[]的超类型)。

您也许认为这一原理同样适用于泛型类型 —— List是 List的超类型,那么可以在需要 List的地方传递 List。不幸的是,情况并非如此。

不允许这样做有一个很充分的理由:

这样做将破坏要提供的类型安全泛型。

如果能够将 List赋给 List。

那么下面的代码就允许将非 Integer的内容放入 List

 

1
2
3
List<integer> li = new ArrayList<integer>();
List<number> ln = li; // illegal
ln.add(new Float(3.1415));</number></integer></integer>

因为 ln是 List,所以向其添加 Float似乎是完全合法的。但是如果 ln是 li的别名,那么这就破坏了蕴含在 li定义中的类型安全承诺 —— 它是一个整数列表,这就是泛型类型不能协变的原因。

分享到:
评论

相关推荐

    关于java泛型的小测试(wildcard,erasure,covariant,raw type)

    在本小测试中,我们将探讨几个与Java泛型相关的概念:通配符(Wildcards)、消除(Erasure)、协变(Covariance)和原始类型(Raw Types)。以下是对这些概念的详细解释: 1. **通配符(Wildcards)** - 通配符是...

    泛型JAVA指南.pdf

    例如,类型擦除(Erasure)是Java泛型的一个重要概念,意味着泛型信息在编译后将被擦除,使得在运行时无法获得泛型类型的详细信息。因此,不能使用instanceof检查泛型类型的参数化形式,只能检查其擦除形式,例如...

    COVARIANT COMPOSITIONAL NETWORKS FOR LEARNING GRAPHS.pdf

    【摘要】:这篇论文提出了一种新的神经网络架构——协变组合网络(Covariant Compositional Networks,简称CCNs),用于学习图结构数据。传统方法通常通过消息传递机制处理图的不变性问题,其中每个节点聚合来自邻居...

    Covariant Script文档(201201)1

    在该语言中,类型系统是其核心部分,包括数值类型、逻辑类型、指针类型、字符类型、字符串类型、数组类型、线性表类型、映射类型等九种基本类型。 在语法方面,Covariant Script支持语句、预处理、关键字、模块、...

    Covariant Script 编程语言解释器

    Covariant Script编程语言解释器是专为处理数据科学、可视化和系统软件开发而设计的一种开源、开放源代码的动态强类型通用编程语言。它的设计理念是提供一个灵活且高效的平台,使得开发者能够更加便捷地进行各种计算...

    affine-covariant-features.tar.gz_Affine_affine covariant

    在图像处理和计算机视觉领域,Affine Covariant Features是一种重要的图像特征检测方法。这些特性具有在仿射变换下保持不变的性质,使得它们在多视角和几何形变的环境中非常有用。"affine-covariant-features.tar.gz...

    图像匹配、图像配准、牛津大学经典图像匹配评估数据集、Affine Covariant Regions Datasets

    资料内容:牛津大学经典图像匹配评估数据集、Affine Covariant Regions Datasets、数据集文件内容主要包含Bikes(模糊变化)、Trees(模糊变化)、Graffiti(视角变化)、Wall(视角变化)、Leuven(光照变化)、UBC...

    Java源码泛型的集合类应用.rar

    6. **原始类型与类型擦除**:Java泛型是通过类型擦除实现的,这意味着在运行时所有的泛型信息都会被移除。为了保持向后兼容,Java允许使用未指定类型的原始类型(如`List`而非`List&lt;String&gt;`),但这样会失去泛型...

    Covariant-Return-Types-and-Smart-Pointers:协变返回类型和智能指针

    协变返回类型和智能指针 协变返回类型是一种语言功能,它允许您将虚函数的返回类型更改为协变类型,即。 指向派生类的指针而不是指向基类的指针 - 请参见下面的示例: struct Figure { virtual ~Figure () = ...

    The Java Programming Language.4th.Edition.Aug.2005.pdf

    - **协变返回类型(Covariant Return Types)**:这种方法允许子类重写父类的方法并改变其返回值的类型,但必须确保子类的返回类型是父类返回类型的子类型。 ##### 3. 新增的关键类 - **Formatter类**:提供了格式...

    南理工java课程设计课件

    自Java 1.5起,接口方法的改写允许返回类型更加宽松,即子接口或实现类的方法返回类型可以是父接口方法返回类型的子类型,这是协变返回类型(covariant return type)。然而,如果方法的返回类型仅仅是不同的,那么...

    java课程资源第七章

    多态(polymorphism) “多态”理解 再论向上转型 多态内部机制 正确使用,私有、静态方法及域与多态关系 构造器-多态 协变的返回类型(Covariant return types) 用继承进行设计(纯继承与扩展、向下转型)

    详解.NET 4.0中的泛型协变(covariant)和反变(contravariant)

    但是两者都增加了一项功能:泛型类型的协变(covariant)和反变(contravariant)。许多人对其了解可能仅限于增加的in/out关键字,而对其诸多特性有所不知。下面我们就对此进行一些详细的解释,帮助大家正确使用该...

    js代码-[CONFIDENTIAL] Covariant Interview Question: Functional Exercise (Javascript)

    "Covariant Interview Question"可能指的是面试中经常出现的关于类型安全和协变性的议题,尤其是在JavaScript这种动态类型的环境中,理解这些概念对于编写健壮的代码至关重要。 【标签】:“代码”——这表明文件...

    IOS应用源码——iPad记事本.zip

    项目中可能使用了可选类型(Optional)或非空类型(nil-covariant/contravariant)来处理可能为null的对象。 7. **多线程编程**:为了提高用户体验,可能会使用GCD(Grand Central Dispatch)或OperationQueue进行...

    你了解C#的协变和逆变吗,看完这篇就懂了

    协变和逆变都是泛型类型系统的一部分,主要用来解决泛型类型之间的继承关系和类型转换问题。 协变(Covariant) 协变是指泛型类型参数可以被隐式地转换为其基类型的能力。这意味着,如果我们有一个泛型类型参数 T...

    Covariant Script 编程语言是一种开源开放的动态强类型通用编程语言,在数据分析、可视化、系统软件方面均有一定的应用

    Covariant Script编程语言,简称CovScript,是一款专为多领域应用而设计的开源、开放源代码的动态强类型编程语言。它以其强大的功能和灵活性,在数据分析、可视化以及系统软件开发等方面展现了广泛的应用潜力。 在...

    Scala编程详解 第19讲-Scala编程详解:类型参数 共13页.pptx

    - 协变和逆变:类型参数可以标记为协变covariant(+T)或逆变contravariant(-T),影响类型参数在多态中的行为。 - Existential Types:用于处理类型参数的“存在”信息,通常在类型系统复杂的情况下使用。 掌握...

    局部协变手性费米子和异常

    本文讨论的主题是“局部协变手性费米子和异常”,这一主题涉及到的是在具有复杂时空背景和规范场的情况下的理论计算,特别是在处理洛伦兹时空结构时出现的手征性问题。以下是对这些概念的详细解读。 首先,局部协变...

Global site tag (gtag.js) - Google Analytics