泛型的基本原理
为什么需要泛型
在Java 5之前,Java的集合类只能存储Object
类型的对象。这意味着,存储在集合中的对象在取出时需要进行类型转换,这不仅繁琐,而且容易出错。泛型通过在编译时进行类型检查,确保类型安全,减少了运行时错误。
泛型的定义
泛型通过类型参数来实现,这些类型参数在使用时被具体的类型替换。常见的类型参数命名如下:
T
:Type(类型)E
:Element(元素)K
:Key(键)V
:Value(值)
泛型类
泛型类是在类定义中使用类型参数。例如:
class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
在使用泛型类时,需要指定具体的类型:
public class GenericClassExample {
public static void main(String[] args) {
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello, World!");
System.out.println(stringBox.getContent()); // 输出: Hello, World!
Box<Integer> integerBox = new Box<>();
integerBox.setContent(123);
System.out.println(integerBox.getContent()); // 输出: 123
}
}
泛型方法
泛型方法是在方法定义中使用类型参数。类型参数在方法名之前用尖括号<>
指定。例如:
public class GenericMethodExample {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4, 5};
String[] stringArray = {"A", "B", "C", "D", "E"};
printArray(intArray); // 输出: 1 2 3 4 5
printArray(stringArray); // 输出: A B C D E
}
}
泛型和集合
Java集合框架是处理一组对象的标准方法。常见的集合包括List
、Set
和Map
。结合泛型使用集合,可以提高类型安全性和代码的可读性。
使用泛型集合
import java.util.ArrayList;
import java.util.List;
public class GenericCollectionExample {
public static void main(String[] args) {
// 创建一个用于存储字符串的泛型列表
List<String> stringList = new ArrayList<>();
// 向列表中添加字符串
stringList.add("Hello");
stringList.add("World");
// 使用增强型 for 循环遍历并打印列表中的每个字符串
for (String str : stringList) {
System.out.println(str);
}
}
}
//程序运行后,输出结果为:
//Hello
//World
在这个例子中,List<String>
确保了stringList
只能包含String
类型的元素。
通配符
通配符用于在泛型中表示未知类型,有三种主要形式:
- 无界通配符:
<?>
,表示任何类型。 - 有界通配符(上界):
<? extends T>
,表示类型T及其子类型。 - 有界通配符(下界):
<? super T>
,表示类型T及其父类型。
无界通配符
无界通配符<?>
表示任何类型。例如:
import java.util.ArrayList;
import java.util.List;
public class WildcardExample {
public static void printList(List<?> list) {
for (Object elem : list) {
System.out.print(elem + " ");
}
System.out.println();
}
public static void main(String[] args) {
List<Integer> intList = new ArrayList<>();
intList.add(1);
intList.add(2);
intList.add(3);
List<String> stringList = new ArrayList<>();
stringList.add("A");
stringList.add("B");
stringList.add("C");
printList(intList); // 输出: 1 2 3
printList(stringList); // 输出: A B C
}
}
有界通配符(上界)
有界通配符<? extends T>
表示类型T及其子类型。例如:
import java.util.ArrayList;
import java.util.List;
public class BoundedWildcardExample {
public static double sumOfList(List<? extends Number> list) {
double sum = 0.0;
for (Number number : list) {
sum += number.doubleValue();
}
return sum;
}
public static void main(String[] args) {
List<Integer> intList = new ArrayList<>();
intList.add(1);
intList.add(2);
intList.add(3);
List<Double> doubleList = new ArrayList<>();
doubleList.add(1.1);
doubleList.add(2.2);
doubleList.add(3.3);
System.out.println("Sum of intList: " + sumOfList(intList)); // 输出: Sum of intList: 6.0
System.out.println("Sum of doubleList: " + sumOfList(doubleList)); // 输出: Sum of doubleList: 6.6
}
}
有界通配符(下界)
有界通配符<? super T>
表示类型T及其父类型。例如:
import java.util.ArrayList;
import java.util.List;
public class LowerBoundedWildcardExample {
public static void addNumbers(List<? super Integer> list) {
list.add(1);
list.add(2);
list.add(3);
}
public static void main(String[] args) {
List<Number> numberList = new ArrayList<>();
addNumbers(numberList);
for (Number number : numberList) {
System.out.println(number);
}
}
}
泛型和继承
泛型不支持多态,例如,List<Number>
不能被赋值为List<Integer>
。但是可以通过使用通配符来实现类似的效果。
示例:泛型和继承
import java.util.ArrayList;
import java.util.List;
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Employee extends Person {
public Employee(String name) {
super(name);
}
}
public class GenericInheritanceExample {
public static void printNames(List<? extends Person> people) {
for (Person person : people) {
System.out.println(person.getName());
}
}
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("Alice"));
employees.add(new Employee("Bob"));
printNames(employees); // 输出: Alice Bob
}
}
总结
通过以上更详细的解释和示例,我们可以更深入地理解泛型和集合的使用:
- 泛型类:定义包含类型参数的类,使用时指定具体类型。
- 泛型方法:定义包含类型参数的方法,使用时指定具体类型。
- 集合和泛型:使用泛型集合可以保证类型安全。
- 通配符:表示未知类型,提供更灵活的类型控制。
- 泛型和继承:使用通配符实现泛型的多态性。