1.运算符 的操作数类型错误 ^ 第一个类型: Object 第二个类型: int:
ListIterator<Integer> it = a.listIterator(); // 关键:加 <Integer>
while (it.hasNext()) {
int val = it.next(); // 现在 val 是 int
if (val % 2 == 0) {
b.add(val);
}
}
2. System.out.println(Arrays.toString(add(a, b).toArray()));
^
需要: List<Integer>,List<Integer>
找到: List,List
final static List a =new ArrayList<>(
Arrays.asList(1,2,3,4,5)
);
final static List b =new ArrayList<>(
Arrays.asList(4,5,6)
);
改成
final static List<Integer> a =new ArrayList<>(
Arrays.asList(1,2,3,4,5)
);
final static List<Integer> b =new ArrayList<>(
Arrays.asList(4,5,6)
);
3.警告: [unchecked] 未经检查的转换
List<Integer> c = add(a, b);
^
需要: List<Integer>
找到: List
static List add(List<Integer> a,List<Integer> b){
List<Integer> c = new ArrayList<>();
for (int i = b.size()-1; i >=0; i--) {
if(a.contains(b.get(i))) c.add(b.get(i));
}
return c;
}
改成:
static List<Integer> add(List<Integer> a,List<Integer> b){
List<Integer> c = new ArrayList<>();
for (int i = b.size()-1; i >=0; i--) {
if(a.contains(b.get(i))) c.add(b.get(i));
}
return c;
}
在 Java 中,只有在 “编译器无法自行推断出类型参数,或者推断出的类型不符合你的意图” 时,才需要显式写出 <Integer>
(或任何其他具体类型实参)。下面按常见场景做一个系统归纳,方便你快速判断“到底要不要写 <Integer>
”。
一、调用 泛型方法 时
1. 必须写 <Integer>
的典型场景
-
方法实参列表为空,因此编译器拿不到任何推断线
Collections.<Integer>emptyList(); // 必须写
-
方法实参存在,但推断结果不是你想要的
Arrays.asList(1, 2, 3); // 推断为 List<Integer>,符合预期,可省 Arrays.asList(1, 2.0); // 推断为 List<Number & Comparable<?>>,不符合预期 <Integer>Arrays.asList(1, 2.0); // 编译错误,类型不兼容 Arrays.<Integer>asList(1, 2.0); // 编译错误,2.0 不是 Integer
-
链式调用,需要中途显式固定类
Optional.<Integer>empty() .orElseThrow();
2. 可以不写 <Integer>
的场景
-
实参已能唯一、正确地推断出类
Collections.singletonList(42); // 推断为 List<Integer>
二、调用 构造方法(泛型类) 时
1. 必须写 <Integer>
的场景
-
菱形语法
<>
未引入前(Java 7 以前List<Integer> list = new ArrayList<Integer>(); // 必须写
-
构造函数本身是泛型方法(很少见
class Foo<T> { <E> Foo(E e) { } } Foo<Integer> f = new <String>Foo<Integer>(""); // 左边 Integer,右边 String
2. 可以不写的场景
-
Java 7+ 支持菱形语
List<Integer> list = new ArrayList<>(); // 可省
三、调用 父类构造器 或 super(...) 时
-
匿名内部类继承泛型父类 时,需要显式指
abstract class Bar<T> {} Bar<Integer> b = new <Integer>Bar<Integer>() {};
四、静态导入 泛型方法 时
-
静态导入后,如果方法不带参数,也必须
import static java.util.Collections.emptyList; List<Integer> list = emptyList(); // 编译错误,无法推断 List<Integer> list = Collections.<Integer>emptyList(); // OK
五、方法引用 / Lambda 中作为 “显式类型实参” 的特例
-
方法引用本身不能写
<Integer
Function<String, Integer> f = Integer::valueOf; // 编译器推断
-
Lambda 表达式体内如果调用泛型方法且需要显式指定,写法与普通调用一
Supplier<List<Integer>> s = () -> Collections.<Integer>emptyList();
六、总结成一句话
只要编译器能根据上下文或实参推断出你想要的
Integer
,就可以不写<Integer>
;否则就必须显式指定。
把常见“必须写”的情况再快速背一遍:
场景 | 必须写 <Integer> 吗? |
---|---|
Collections.<Integer>emptyList() | ✅ |
new ArrayList<>() (Java 7+) | ❌ |
new ArrayList<Integer>() (Java 6) | ✅ |
Arrays.asList(1, 2) | ❌ |
Arrays.<Integer>asList(1, 2) | ❌(画蛇添足) |
new <String>Foo<Integer>(...) | ✅(泛型构造) |
super(…) / this(…) 调用父类泛型构造 | 视推断而定 |
记住这些典型例子,实际编码时就能一眼判断要不要加 <Integer>
。
我是伏琪,关注订阅号伏琪了解更多。