`
silentJesse
  • 浏览: 107515 次
  • 性别: Icon_minigender_1
  • 来自: 福建厦门
社区版块
存档分类
最新评论

对泛型之不能协变(convariant)的理解,以及不能协变导致的问题

阅读更多
1.何为协变
假设有一个接口,以及一个他的实现类
如下:
接口为:
public interface GenericsInterface {
	void test();
}


其实现类为:
public class Type2 implements GenericsInterface{
	int i = 2;
	public void test(){
		System.out.println(i);
	}
	
}



//子类的对象可以直接为父类的句柄进行引用,即为是可以协变的
GenericsInterface gi = new Type2();


2.泛型是不能协变的
在1的情况下添加一个类G1
public class G1<T> {
	private T i = null;
	public void print(){
		System.out.println(i);
	}
	public T getI() {
		return i;
	}
	public void setI(T i) {
		this.i = i;
	}
 
}


测试代码如下:
//子类的对象可以直接为父类的句柄进行引用,即为是可以协变的
GenericsInterface gi = new Type2();


//以子类SUBTYPE作为泛型参数的A类对象
//是不能由以SUBTYPE的父类作为泛型参数的A类句柄所引用,即为不可协变
G1<GenericsInterface> g4 = new G1<Type2>();//invalid


由1,2两点可以推出以下的结论:
(1)子类的对象可以直接为父类的句柄进行引用,即为是可以协变的
(2)以子类SUBTYPE作为泛型参数的A类对象是不能由以SUBTYPE的父类TYPE作为泛型参数的A类句柄所引用,即为不可协变


3.java为什么要让泛型不能协变呢?
请看以下的示例
List<Integer> li = new ArrayList<Integer>(); 
List<Number> ln = li; // illegal 
ln.add(new Float(3.1415)); 

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


4.泛型不能协变导致的问题
如下示例
G1[] g1array = new G1[3];
G1<String>[] g1array2 = new G1<String>[3];//invalid
G1<?>[] g1array3 = new G1<?>[3];


为什么当数组中的G1类的泛型参数具体化后变成invalid的呢?
也就是说在实例化G1数组,往G1数组添加成员之前,就把泛型参数具体指定时,是非法的

由以下可以看出原因
List<String>[] lsa = new List<String>[10]; // illegal 
Object[] oa = lsa;//OK because List<String> is a subtype of Object 
List<Integer> li = new ArrayList<Integer>(); 
li.add(new Integer(3)); 
oa[0] = li; 
String s = lsa[0].get(0); 


最后一行将抛出 ClassCastException,因为这样将把 List<Integer>填入本应是 List<String>的位置。因为数组协变会破坏泛型的类型安全,所以不允许实例化泛型类型的数组(除非类型参数是未绑定的通配符,比如 List<?>)。



分享到:
评论

相关推荐

    Java语言 泛型讲解案例代码 (泛型类、泛型接口、泛型方法、无界及上下限通配符、泛型对协变和逆变的支持、类型擦除 ...)

    读者可以通过运行这些示例代码来观察泛型的行为和效果,进一步加深对泛型的理解。 代码资源中会包含以下示例代码: 定义泛型类:展示如何定义一个简单的泛型类,以及如何创建该类的实例并使用泛型参数。 泛型方法:...

    C# 泛型接口的抗变和协变

    在C#中,泛型接口的抗变和协变是两个关键的概念,它们涉及到类型参数在接口中的使用方式,以及如何允许更灵活的类型转换。这些特性使得代码更具通用性和可扩展性。 首先,让我们详细解释一下这两个概念: 1. 泛型...

    理解C#中的协变和逆变

    在C#编程语言中,协变(Covariance)和逆变(Contravariance)是两个重要的概念,它们与类型系统、接口和泛型密切相关,主要用于增强代码的灵活性和重用性。理解这两个概念对于编写高效、可维护的C#程序至关重要。 ...

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

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

    泛型之FormDemo

    在这个例子中,开发者可能已经展示了如何创建泛型窗体,如何定义泛型UserControl,以及如何利用反射来动态地处理不同类型的界面元素和业务逻辑。通过学习这个示例,开发者可以学习到如何在实际项目中有效地应用泛型...

    对泛型的理解

    本人对泛型的一些理解,刚看就先了下。一些没有多余的时间去理解,所以没提到,时间仓促,只能借鉴

    C#泛型类、泛型方法、泛型接口、泛型委托的实例

    本文将深入探讨泛型类、泛型方法、泛型接口和泛型委托,并通过实例来阐述它们的应用。 首先,我们来看泛型类。泛型类是具有一个或多个类型参数的类。类型参数是在定义类时使用的占位符,实际的类型在创建类的实例时...

    java泛型技术之发展

    本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展历程** - **早期版本的局限**:在Java泛型出现之前,程序员通常使用Object作为容器类(如ArrayList、HashMap等)的默认类型...

    泛型dao 泛型dao 泛型dao

    能不能不写重复的dao 呢 ? 泛型dao,顾名思义就是一个dao可以对多个实体对象进行持久化。当应用中需要使用到上十张表时,DAO的维护变得日益困难,主要表现在这几个方面: 1)dao类的繁多,很多设计都是一个...

    泛型java的泛型知识,非常有用

    Java 泛型是一种强大的语言特性,自JDK 5.0引入以来,极大地提升了代码的类型安全性以及重用性。泛型允许我们在类、接口和方法中使用类型参数,这样在编译时期就能检查类型匹配,减少运行时类型转换异常。 1. **...

    java泛型学习

    - **泛型类型数组的限制**:由于泛型类型不能协变,因此不允许实例化泛型类型的数组,如 `new List[3]` 是非法的。唯一例外是使用未绑定的通配符,如 `new List[3]` 是合法的。 #### 五、构造延迟 - **类型擦除的...

    泛型知识总结

    本文将深入探讨泛型的应用、原理、协变与逆变以及泛型缓存等核心知识点。 首先,让我们理解泛型的基本概念。泛型允许我们在类、接口和方法中使用类型参数,这样在编译时就能检查类型安全,避免了运行时的类型转换...

    关于C#、java泛型的看法

    C#的泛型支持协变和逆变,这意味着在某些情况下,派生类型的对象可以赋值给基类型引用,即使泛型类型本身不兼容。此外,C#还提供了泛型约束,如where关键字,允许开发者指定类型参数必须遵循的规则,如必须包含某个...

    Java泛型技术之发展.pdf

    - 在可能的情况下,使用协变(`? extends T`)和逆变(`? super T`)来增加方法的灵活性。 - 对于静态方法,通常不建议使用泛型,因为静态方法与类的实例无关,无法利用类型参数。 通过理解并熟练运用Java泛型,...

    Java泛型技术之发展

    本文将深入探讨泛型技术的概念、历史背景、与其它编程概念的区别,以及其在Java语言中的具体应用。 ### 泛型技术概览 泛型技术起源于1968年Doug McIlroy的一篇论文“Mass Produced Software Components”,在这篇...

    JVM如何理解Java泛型类.doc

    然而,对于Java虚拟机(JVM)来说,它实际上并不理解泛型的概念。所有的泛型信息在编译阶段就被擦除了,留下的只是普通的Java类和方法。本文将深入探讨Java泛型类的工作原理以及JVM是如何处理这些泛型类的。 #### 二...

    C# 之泛型详解

    当尝试向整数栈`Stack&lt;int&gt;`推送字符串或者从字符串栈`Stack&lt;string&gt;`弹出整数时,编译器会报错,防止了潜在的类型不匹配问题。 泛型的使用不仅仅局限于栈。它还可以应用于集合类,如`List&lt;T&gt;`和`Dictionary, ...

Global site tag (gtag.js) - Google Analytics