首先,泛型不具备继承性,但是数据具备继承性
1.核心概念解析
泛型不具备继承性
- 即使类型A是类型B的子类,
Generic<A>
也不是Generic<B>
的子类 - 这是Java泛型的类型安全设计,防止不安全的类型转换
数据具备继承性
- 泛型容器中的元素仍遵循Java继承规则
- 可以通过通配符(
extends
/super
)在泛型中利用数据的继承关系
import java.util.*;class Animal {void eat() {System.out.println("Animal eating");}
}class Dog extends Animal {void bark() {System.out.println("Dog barking");}
}public class GenericInheritanceDemo {public static void main(String[] args) {// 1. 泛型不具备继承性演示List<Animal> animals = new ArrayList<>();List<Dog> dogs = new ArrayList<>();// 编译错误:泛型不具备继承性// animals = dogs; // 错误: 不兼容的类型// 2. 数据具备继承性演示// 创建混合动物列表List<Animal> animalList = new ArrayList<>();animalList.add(new Dog()); // √ Dog是Animal子类animalList.add(new Cat()); // √ Cat是Animal子类}
}
2.泛型通配符详解
泛型通配符是Java泛型中处理未知或不确定类型的重要机制,主要有三种形式:
(1). 无界通配符 <?>
表示可以接受任何类型的参数化类型。
public static void printList(List<?> list) {for (Object item : list) {System.out.print(item + " ");}System.out.println();
}// 使用示例
List<String> stringList = Arrays.asList("A", "B", "C");
List<Integer> intList = Arrays.asList(1, 2, 3);
printList(stringList); // 输出:A B C
printList(intList); // 输出:1 2 3
(2). 上界通配符 <? extends T>
表示参数化类型是T或其子类,用于"生产者"场景(从结构中获取元素)。
public static double sum(List<? extends Number> list) {double sum = 0.0;for (Number num : list) {sum += num.doubleValue();}return sum;
}// 使用示例
List<Integer> intList = Arrays.asList(1, 2, 3);
List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);
System.out.println(sum(intList)); // 输出:6.0
System.out.println(sum(doubleList)); // 输出:6.6
(3). 下界通配符 <? super T>
表示参数化类型是T或其父类,用于"消费者"场景(向结构中添加元素)。
public static void addNumbers(List<? super Integer> list) {for (int i = 1; i <= 5; i++) {list.add(i);}
}// 使用示例
List<Object> objectList = new ArrayList<>();
addNumbers(objectList);
System.out.println(objectList); // 输出:[1, 2, 3, 4, 5]
3.综合示例代码
编写一个方法,该方法接受一个列表并检查其中是否包含特定元素。如果包含,则返回该元素;否则,返回默认值。
import java.util.List;public class WildcardDemo {public static <T> T findElementOrDefault(List<T> list, T element, T defaultValue) {for (T item : list) {if (item.equals(element)) {return item;}}return defaultValue;}public static void main(String[] args) {List<String> stringList = List.of("Apple", "Banana", "Cherry");List<Integer> intList = List.of(1, 2, 3);String foundString = findElementOrDefault(stringList, "Banana", "Not Found");Integer foundInt = findElementOrDefault(intList, 4, -1);System.out.println("Found String: " + foundString); // 输出:Found String: BananaSystem.out.println("Found Int: " + foundInt); // 输出:Found Int: -1}
}
4.关键点解释
泛型不具备继承性
List<Dog>
不能赋值给List<Animal>
(编译错误)- 防止将
Cat
添加到Dog
列表中破坏类型安全
数据具备继承性
Dog
对象可以添加到List<Animal>
中(向上转型)- 在
List<Animal>
中可以调用所有Animal
的方法
通配符连接泛型与继承
<? extends Animal>
:接受所有Animal子类的列表<? super Animal>
:接受所有Animal父类的列表- 通配符在泛型系统中建立与继承体系的连接
类型转换规则
- 泛型容器内元素可以安全向上转型
- 向下转型需要显式类型检查和转换
- 通配符在编译时保证类型安全操作
什么时候使用<T>
,什么时候使用<?>
- 使用
<T>
当你需要:- 声明类型变量
- 在方法或类中引用该类型
- 需要向集合中添加元素
- 使用
<?>
当你:- 只关心读取集合中的元素
- 不需要知道具体类型
- 不需要向集合中添加元素
设计本质:Java泛型通过"类型擦除"实现,运行时所有泛型类型都变成Object。通配符系统是在编译器层面建立的类型安全规则,利用继承体系实现灵活性与类型安全的平衡。
5.PECS原则(Producer-Extends, Consumer-Super)
原则解析
- Producer-Extends: 当需要从数据结构获取数据时使用
<? extends T>
- Consumer-Super: 当需要向数据结构存入数据时使用
<? super T>
本文探讨了Java泛型与继承的关系。泛型本身不具备继承性(如List<Dog>不是List<Animal>的子类),但容器中的元素仍遵循继承规则。通过上界通配符<? extends T>可接受T及其子类,下界通配符<? super T>可接受T及其父类。泛型方法利用类型参数<T extends Animal>可实现安全类型转换。这些特性在编译时确保类型安全,防止运行时错误,同时灵活利用继承关系处理不同类型数据。