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<?>)。
分享到:
相关推荐
读者可以通过运行这些示例代码来观察泛型的行为和效果,进一步加深对泛型的理解。 代码资源中会包含以下示例代码: 定义泛型类:展示如何定义一个简单的泛型类,以及如何创建该类的实例并使用泛型参数。 泛型方法:...
在C#中,泛型接口的抗变和协变是两个关键的概念,它们涉及到类型参数在接口中的使用方式,以及如何允许更灵活的类型转换。这些特性使得代码更具通用性和可扩展性。 首先,让我们详细解释一下这两个概念: 1. 泛型...
在C#编程语言中,协变(Covariance)和逆变(Contravariance)是两个重要的概念,它们与类型系统、接口和泛型密切相关,主要用于增强代码的灵活性和重用性。理解这两个概念对于编写高效、可维护的C#程序至关重要。 ...
但是两者都增加了一项功能:泛型类型的协变(covariant)和反变(contravariant)。许多人对其了解可能仅限于增加的in/out关键字,而对其诸多特性有所不知。下面我们就对此进行一些详细的解释,帮助大家正确使用该...
在这个例子中,开发者可能已经展示了如何创建泛型窗体,如何定义泛型UserControl,以及如何利用反射来动态地处理不同类型的界面元素和业务逻辑。通过学习这个示例,开发者可以学习到如何在实际项目中有效地应用泛型...
本人对泛型的一些理解,刚看就先了下。一些没有多余的时间去理解,所以没提到,时间仓促,只能借鉴
本文将深入探讨泛型类、泛型方法、泛型接口和泛型委托,并通过实例来阐述它们的应用。 首先,我们来看泛型类。泛型类是具有一个或多个类型参数的类。类型参数是在定义类时使用的占位符,实际的类型在创建类的实例时...
本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展历程** - **早期版本的局限**:在Java泛型出现之前,程序员通常使用Object作为容器类(如ArrayList、HashMap等)的默认类型...
能不能不写重复的dao 呢 ? 泛型dao,顾名思义就是一个dao可以对多个实体对象进行持久化。当应用中需要使用到上十张表时,DAO的维护变得日益困难,主要表现在这几个方面: 1)dao类的繁多,很多设计都是一个...
Java 泛型是一种强大的语言特性,自JDK 5.0引入以来,极大地提升了代码的类型安全性以及重用性。泛型允许我们在类、接口和方法中使用类型参数,这样在编译时期就能检查类型匹配,减少运行时类型转换异常。 1. **...
- **泛型类型数组的限制**:由于泛型类型不能协变,因此不允许实例化泛型类型的数组,如 `new List[3]` 是非法的。唯一例外是使用未绑定的通配符,如 `new List[3]` 是合法的。 #### 五、构造延迟 - **类型擦除的...
本文将深入探讨泛型的应用、原理、协变与逆变以及泛型缓存等核心知识点。 首先,让我们理解泛型的基本概念。泛型允许我们在类、接口和方法中使用类型参数,这样在编译时就能检查类型安全,避免了运行时的类型转换...
C#的泛型支持协变和逆变,这意味着在某些情况下,派生类型的对象可以赋值给基类型引用,即使泛型类型本身不兼容。此外,C#还提供了泛型约束,如where关键字,允许开发者指定类型参数必须遵循的规则,如必须包含某个...
- 在可能的情况下,使用协变(`? extends T`)和逆变(`? super T`)来增加方法的灵活性。 - 对于静态方法,通常不建议使用泛型,因为静态方法与类的实例无关,无法利用类型参数。 通过理解并熟练运用Java泛型,...
本文将深入探讨泛型技术的概念、历史背景、与其它编程概念的区别,以及其在Java语言中的具体应用。 ### 泛型技术概览 泛型技术起源于1968年Doug McIlroy的一篇论文“Mass Produced Software Components”,在这篇...
然而,对于Java虚拟机(JVM)来说,它实际上并不理解泛型的概念。所有的泛型信息在编译阶段就被擦除了,留下的只是普通的Java类和方法。本文将深入探讨Java泛型类的工作原理以及JVM是如何处理这些泛型类的。 #### 二...
当尝试向整数栈`Stack<int>`推送字符串或者从字符串栈`Stack<string>`弹出整数时,编译器会报错,防止了潜在的类型不匹配问题。 泛型的使用不仅仅局限于栈。它还可以应用于集合类,如`List<T>`和`Dictionary, ...