周末研究了下java泛型,关于泛型通配符的协变与逆变问题,题目如下:
- 题目要求:创建一个泛型类Generic1<T>,它只有一个方法,将接受一个T类型的参数。创建第二个泛型类Generic2<T>,它也只有一个方法,将返回类型T的参数。编写一个泛型方法,它具有一个调用第一个泛型类的方法的逆变参数。编写第二个泛型方法,它具有一个调用第二个泛型类的方法的协变参数。
- 实例代码如下:
package generics.exercises;
import java.util.ArrayList;
import java.util.List;
import typeinfo.pets.Dog;
public class ContraVarianceAndCovariant {
static class Generic1Sup<T> {
}
static class Generic1<T> extends Generic1Sup<T> {
void setT(T t) {
}
}
static class Generic1Sub<T> extends Generic1<T> {
}
static class Generic2Sup<T> {
}
static class Generic2<T> extends Generic2Sup<T> {
T getT(T t) {
return t;
}
}
static class Generic2Sub<T> extends Generic2<T> {
}
static <T> void writeWithWildcard(List<? super T> list, T item) {
list.add(item);
}
static <T> T readCovariant(List<? extends T> list) {
return list.get(0);
}
static List<Generic1<Dog>> dogs = new ArrayList<Generic1<Dog>>();
static List<Generic1Sup<Dog>> dogsSup = new ArrayList<Generic1Sup<Dog>>();
static List<Generic1Sub<Dog>> dogsSub = new ArrayList<Generic1Sub<Dog>>();
static List<Generic2<Dog>> dogs2 = new ArrayList<Generic2<Dog>>();
static List<Generic2Sup<Dog>> dogs2Sup = new ArrayList<Generic2Sup<Dog>>();
static List<Generic2Sub<Dog>> dogs2Sub = new ArrayList<Generic2Sub<Dog>>();
static void f1() {
writeWithWildcard(dogs, new Generic1<Dog>());
writeWithWildcard(dogsSup, new Generic1<Dog>());
// ! writeWithWildcard(dogsSub, new Generic1<Dog>());
Generic1<Dog> generic1 = dogs.get(0);
generic1.setT(new Dog("dog1"));
System.out.println(generic1);
}
static void f2() {
Generic2<Dog> generic2 = readCovariant(dogs2);
generic2 = (Generic2<Dog>) readCovariant(dogs2Sup);
generic2 = readCovariant(dogs2Sub);
generic2.getT(new Dog("dog2"));
System.out.println(generic2);
}
static class CovariantReader<T> {
T readCovariant(List<? extends T> list) {
return list.get(0);
}
}
static void f3() {
CovariantReader<Generic2<Dog>> fruitReader = new CovariantReader<Generic2<Dog>>();
Generic2<Dog> generic2 = fruitReader.readCovariant(dogs2);
// ! generic2 = fruitReader.readCovariant(dogs2Sup);
generic2 = fruitReader.readCovariant(dogs2Sub);
generic2.getT(new Dog("dog2"));
}
}
感兴趣的读者可以研究下,为题目提供更好的解决方案。
分享到:
相关推荐
学习和理解Java泛型的基本概念和语法; 实际项目中需要使用泛型来增加类型安全性和重用性的开发任务。 目标: 本代码资源的目标是帮助读者理解泛型的用法和优势,并通过实际的示例代码加深对泛型的掌握。读者可以...
这意味着Java的泛型不支持协变和逆变,但可以通过通配符(如?)来放宽类型限制。Java的泛型约束则相对较少,主要通过extends和super关键字来限制类型参数的范围。 在实际应用中,C#的泛型在效率上可能具有优势,...
- 但是,泛型不支持协变(Covariance)和逆变(Contravariance),所以 `List<Dog>` 不是 `List<Animal>` 的子类型。 8. 类型推断(Type Inference): - 自Java 7起,编译器可以自动推断泛型的类型,例如在创建...
但是,通过使用通配符,我们可以实现协变(如`List<? extends Number>`可以赋值给`List<Number>`)和逆变(如`List<? super Integer>`可以赋值给`List<Object>`)。 4. **类型参数的约束**:在定义泛型类或接口时,...
8. **类型参数的协变和逆变**:在处理泛型集合时,了解协变和逆变的概念非常重要。比如,`List<Number>`是`List<Object>`的子类型,这称为协变;而`List<? extends Number>`可以赋值给`List<Number>`,这称为逆变。 ...
- 在可能的情况下,使用协变(`? extends T`)和逆变(`? super T`)来增加方法的灵活性。 - 对于静态方法,通常不建议使用泛型,因为静态方法与类的实例无关,无法利用类型参数。 通过理解并熟练运用Java泛型,...
6. **协变和逆变**:理解如何在泛型中实现类型参数的协变和逆变。 7. **比较和equals**:在泛型上下文中正确地实现Comparable和equals()方法。 8. **枚举类型与泛型**:结合使用枚举和泛型来增强类型安全。 通过...
super SomeClass`表示任何`SomeClass`或其父类的对象,但Java中不支持下界通配符的写法,一般通过协变(covariance)和逆变(contravariance)实现类似功能。 6. 类型擦除 - Java的泛型是通过类型擦除实现的,这...
5. **协变与逆变**: 在泛型中,类型参数的使用会影响类型安全。比如,List是List的子类型(协变),而List不是List的子类型(逆变)。 在实际开发中,理解和熟练运用Java集合框架和泛型能够大大提高代码的可维护性...
6. **协变与逆变:**Java泛型支持协变和逆变,这是在处理泛型接口和类时的重要特性。协变允许子类型替换父类型,而逆变则允许父类型替换子类型。在并发编程中,了解这些概念有助于编写更灵活和安全的代码。 7. **...
5. **协变与逆变**:泛型的协变(Covariance)和逆变(Contravariance)主要涉及集合类的使用。比如,`List<Number>`是`List<Object>`的子类型,这是协变;而`Comparator<Number>`不是`Comparator<Object>`的子类型...
10. **协变与逆变**:泛型的协变和逆变涉及到类型参数的位置以及它们如何影响方法签名的兼容性。例如,`List<? extends Number>` 是协变的,因为它允许更具体的子类型作为参数;而 `Comparator<? super T>` 是逆变的...
为了实现协变(Covariance)和逆变(Contravariance),可以使用通配符的上界和下界。 **泛型方法:** 除了泛型类,我们还可以定义泛型方法,它们在方法签名中使用类型参数: ```java public static <T> void swap...
- 泛型接口和泛型类可以作为参数传递,利用协变和逆变的概念,增强代码的兼容性。 8. 泛型与继承: - 泛型类的子类可以选择继承父类的类型参数,或者指定自己的类型参数。 - 泛型方法的重写需要保持类型参数的...
7. **协变与逆变**:在Java中,泛型是协变的,意味着`List<Number>`是`List<Object>`的子类型,这允许将Number列表赋值给Object列表。然而,对于泛型的参数类型,它是逆变的,例如`List<? super Integer>`可以接受...
10. **协变与逆变**:在泛型中,我们还可以讨论协变(covariant)和逆变(contravariant)的概念。简单来说,如果子类型可以赋值给父类型,那么这种关系在泛型中被称为协变;反之,如果父类型可以赋值给子类型,那么...
它支持协变、逆变等高级特性,但在使用中需要注意类型擦除带来的影响,并通过通配符、类型边界等方法解决泛型在使用中可能遇到的问题。 类型擦除(Type Erasure)是Java泛型的一种机制,它在运行时移除泛型信息,以...
9. **协变与逆变**:泛型的协变和逆变是两个重要的概念。泛型默认是不变的,但可以通过使用 `extends` 和 `super` 关键字来实现协变和逆变,以增强集合的使用灵活性。例如,`List<? extends Number>` 是协变的,可以...
泛型通配符用于表示对类型参数的不确定范围。常见的通配符有 `?`(无边界)、`? extends SomeType`(上界通配符)和 `? super SomeType`(下界通配符)。例如,当我们想要一个方法接受任何类型的List,但不关心具体...
**Java泛型是JDK1.5引入的一个重要特性,极大地提高了代码的类型安全性和重用性。在泛型出现之前,程序员需要在运行时进行强制类型转换,这可能导致ClassCastException。泛型通过在类、接口和方法声明中引入类型参数...