一筐梨子&一筐水果——协变性(covariant)

假设突然看见这个问题。我们常常会想当然。

一个梨子是水果,一筐梨子是一筐水果吗?

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXFqMjA2NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

程序中,我们较少使用到协变性(covariant)。

一个经典的问题:父类Sup有方法m()。有子类Sub

public class CovariantDemo{
    public static void main(String[] args) {
        Sub[] b = new Sub[10];
        Sup[] p = b;

        p[0] =  new Sup();
        b[0].m();
    }
}

有什么问题?

b是一筐梨子。p是一筐水果,如今你把一个苹果放在了p中。

所以,编译器觉得正确。执行时java.lang.ArrayStoreException: typeSystem.generics.Sup

Java泛型中最令人头痛的是參数化类型的协变性问题。

数组的一个重要性质——协变性(covariant):假设A是B的子类。则A[]是B[]的子类型。

然而对于泛型C<T>,參数化类型C<Object>与C<String>无关。

这违反人们的直观认知

如何说服自己:C<Object>与C<String>无关是合理的。

(1)參数化类型C<梨子>保证当前有一筐梨子。而C<水果>则保证当前有一筐水果,能够向一筐水果中放入苹果、菠萝。假设C<水果>持有C<梨子>引用却不导致编译错误的话,就能够向一筐梨子中放入苹果、菠萝。那么泛型的作用——保证/限定泛型中元素类型的作用将荡然无存。(技术原因:类型參数的擦除)

(2)尽管数组具有协变性,可是在使用时,程序猿要自律地限制元素类型、须要做强制类型转换、或者须要忍受执行时异常而非编译时错误。而这些正是Java泛型要避免的,Java泛型比Java数组使用起来更安全。还有一方面,由于可以方便地使用有限定性的数组如“梨子[]”,数组的协变性不被常常使用。也就不显得讨厌。

(修复例程问题:p[0] =  new Sub(); )

A是B的子类型。參数化类型C<A> 与C<B>无协变性。在某些情况下,却须要參数化类型可以协变,注意,协变指參数化类型之间的协变。为此,Java提供通配符(wildcard)。包含仅仅读通配符“? extends”和仅仅写通配符“?super”。

【5.4.2】

时间: 2024-12-25 17:05:49

一筐梨子&amp;一筐水果——协变性(covariant)的相关文章

一筐梨子&amp;一筐水果——协变性(covariant)

如果突然看见这个问题,我们经常会想当然.一个梨子是水果,一筐梨子是一筐水果吗? 程序中,我们较少使用到协变性(covariant).一个经典的问题:父类Sup有方法m(),有子类Sub public class CovariantDemo{ public static void main(String[] args) { Sub[] b = new Sub[10]; Sup[] p = b; p[0] = new Sup(); b[0].m(); } } 有什么问题? b是一筐梨子,p是一筐水果

数组的协变性与范型的不可变性

记得以前面试的时候曾被问过一个问题:数组和List的区别是什么?当时答的无非就是效率,容量固定,List不能存基本类型等等.当Java发展到了1.5之后,出现了泛型版本的List,又为这个问题的解答加入了一笔.下面就来讲一下与这个话题相关的内容. 1. 数组的协变性 数组的协变性(covariant)是指如果类Base是类Sub的基类,那么Base[]就是Sub[]的基类.而泛型是不可变的(invariant),List<Base>不会是List<Sub>的基类,更不会是它的子类.

智力题小结(3)

1.有7克.2克砝码各一个,天平一只,如何只用这些物品三次将140克的盐分成50.90克各一份? 答案: 第一步:把140克盐分成两等份,每份70克. 第二步:把天平一边放上2+7克砝码,另一边放盐,这样就得到9克和61克分开的盐. 第三步:将9克盐和2克砝码放在天平一边,另一边放盐,这样就得到11克和50克.于是50和90就分开了. 2. 国王招来100个囚犯,对他们说:你们犯的是死罪,但我给你们一次求生的机会.15分钟以后,你们将被关进一个有100间隔离牢房的监狱里,每人一间牢房,都与外界隔

java面试智力题

智力题,每个正式的笔试.面试都会出,而且在面大企业的时候必然会问到,笔者曾在很多面试中,都被问到过,不过答得都不是很好,因为时间很短,加上我们有时候过于紧张,所以做出这类问题,还是有一定的难度,从这篇文章中我会总结一些常见的智力题,希望各位读者能在本章所列的题中找出做这类题的方法,克服面试中的难题! 1.农民分金条问题 题目:你让农民为你工作7天,给他的回报是一根金条.金条平分成相连的7段,你必须在每天结束时给他们一段金条,如果只许你两次把金条弄断,你如何 给你的工人付费,保证该农民在七天中任意

D: Divide the pears

提交: 20 解决: 18 题目描述 Macro非常喜欢吃梨,有一天他得到了ACMICPC组委会送给他的一筐梨子.他比较心疼学生,就打算把梨子分给学生吃.现在他要把M个梨子放到N个盘子里面 (我们允许有的盘子为空) ,你能告诉Macro有多少种分法吗? (请注意,如果有三个盘子,我们将5,1,1和1,1,5,视为同一种分法) 输入 第一行是一个整数t,代表有t组样例. 第二行有两个整数M 和 N 代表有M个梨和N个盘子. 输出 输出有多少种方法 样例输入 1 7 3 样例输出 8 1 #incl

程序员智力题

1.考虑一个双人游戏.游戏在一个圆桌上进行.每个游戏者都有足够多的硬币.他们需要在桌子上轮流放置硬币,每次必需且只能放置一枚硬币,要求硬币完全置于桌面内(不能有一部分悬在桌子外面),并且不能与原来放过的硬币重叠.谁没有地方放置新的硬币,谁就输了.游戏的先行者还是后行者有必胜策略?这种策略是什么? 答案:先行者在桌子中心放置一枚硬币,以后的硬币总是放在与后行者刚才放的地方相对称的位置.这样,只要后行者能放,先行者一定也有地方放.先行者必胜. 2. 用线性时间和常数附加空间将一篇文章的单词(不是字符

脑洞打开,智力题

1,有50个球,你和你的对手轮流取,你先开始,每次最多取6个,最少取1个,问你怎么可以保证自己一定可以得到最后一个球? 2,两个机器人,初始时位于数轴上的不同位置.给这两个机器人输入一段相同的程序,使得这两个机器人保证可以相遇.程序只能包含“左移n个单位”.“右移n个单位”,条件判断语句If,循环语句while,以及两个返回Boolean值的函数“在自己的起点处”和“在对方的起点处”.你不能使用其它的变量和计数器. 3,某种药方要求非常严格,你每天需要同时服用A.B两种药片各一颗,不能多也不能少

[Thinkbayes]贝叶斯思维读书笔记-1-贝叶斯定理

使用贝叶斯定理,目前来看最重要的一点在于假设.就是未知事件已知化,同时也要注意假设的全程性,不能从中开始新的假设,这种假设往往是不全面的. 我自己找到的假设的方法有两种,一种是命名,一种是时序.全程性就体现在时序上了,假设考虑的范围要从第一条相关条件开始. 举3个原书的例子: 例子1,有两个筐,一个筐A中是:3/4的红球,1/4的黄球:另一个筐B中是:1/2的红球,1/2的黄球. 我拿到了一个红球,那么这个红球从筐A中拿到的概率是多少? 1,我们看一下能不能使用贝叶斯公式?这个事件可以分为两个子

算法--快速排序(链表)

快速排序 http://m.blog.csdn.net/blog/u013071074/36867589 快速排序是由C. A. R. Hoare所发展的一种排序算法.其基本思想是基本思想是,通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序. 快速排序使用分治法来把一个串(list)分为两个子串行(sub-lists). 步骤为: 1.从数列中挑出一个元素,称为 "基准"(pivot), 2.