泛型 中的 T
和通配符 ?
确实都可以表示未知的类型,但它们在使用场景和语法上有一些不同之处。让我详细解释一下它们的区别,并举例说明。
泛型 T
泛型 T
是一种类型参数,用于在定义类、接口或方法时表示一种未知的类型。它通常在类或方法的声明中使用,并且可以用来增加代码的灵活性和类型安全性。
主要特点:
- 泛型
T
在定义时可以指定上限(bounded type),例如T extends Number
表示T
可以是Number
类型或其子类。 - 在实际使用时,
T
会被具体的类型替换,使得编译器能够进行类型检查和类型推断。 - 泛型
T
的实际类型由调用时提供的具体类型参数确定。
示例:
public class Box<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<>();
integerBox.setValue(123);
System.out.println("Integer value: " + integerBox.getValue());
Box<String> stringBox = new Box<>();
stringBox.setValue("Hello");
System.out.println("String value: " + stringBox.getValue());
}
}
在这个例子中,Box<T>
是一个泛型类,T
是一个类型参数,它可以根据实际情况被替换为具体的类型,例如 Integer
或 String
。
通配符 ?
通配符 ?
是一种用于声明时或方法参数中的特殊符号,用于表示未知的具体类型。它通常与泛型类或泛型方法一起使用,用于增加代码的灵活性,但不同于泛型 T
,它并不是一个具体的类型,而是一个通配符,可以表示任意类型。
主要特点:
- 通配符
?
通常用于方法的参数中,允许传入不同类型的泛型对象。 - 可以使用上限通配符
? extends SomeType
和下限通配符? super SomeType
来限制通配符的范围。
示例:
import java.util.ArrayList;
import java.util.List;
public class WildcardExample {
public static double sum(List<? extends Number> list) {
double sum = 0;
for (Number n : list) {
sum += n.doubleValue();
}
return sum;
}
public static void main(String[] args) {
List<Integer> integers = new ArrayList<>();
integers.add(3);
integers.add(5);
integers.add(7);
double result = sum(integers);
System.out.println("Sum of integers: " + result);
List<Double> doubles = new ArrayList<>();
doubles.add(2.5);
doubles.add(3.5);
doubles.add(4.5);
double result2 = sum(doubles);
System.out.println("Sum of doubles: " + result2);
}
}
在这个例子中,sum
方法使用了 List<? extends Number>
的通配符作为参数类型,表示可以接受任意扩展自 Number
的泛型列表。这样,sum
方法可以用来计算 Integer
或 Double
类型的列表的和。
区别总结
- 泛型
T
是一种类型参数,用于在类或方法的声明中表示一种具体的类型,可以在编译时进行类型检查。 - 通配符
?
是一种通用的符号,用于声明时或方法参数中,表示任意未知类型,通常与泛型类或方法一起使用,用于增加代码的灵活性。
选择使用泛型 T
还是通配符 ?
取决于具体的需求和语境,通常来说,如果需要在类或方法内部使用该类型进行一些具体操作,应该选择泛型 T
;而如果只需要接受或返回某种类型而不关心具体类型的操作,则可以使用通配符 ?
。