Java 泛型 - 参数中的相等约束
Java Generics - Equality constraint in parameters
设想以下 class 层次结构:
Cake
\- ChocolateCake
\- StuffedChocolateCake
\- VanillaCake
我想写一个方法来组合 ChocolateCake 和 VanillaCake 的列表,例如:
public static <T extends Cake> List<T> union(List<T> listA, List<T> listB) {
List<T> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
这会抛出一个编译错误,我的理解是:
inferred type does not conform to equality constraint(s)
我尝试通过以下方式删除等式约束:
public static List<? extends Cake> union(List<? extends Cake> listA, List<? extends Cake> listB) {
List<? extends Cake> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
我想这是 Java 泛型的一个相当基本的场景,正确的方法是什么?
提前感谢您的宝贵时间!
将 return 类型更改为 List<Cake>
,您的第二个版本应该可以正常工作:
public static List<Cake> union(List<? extends Cake> listA, List<? extends Cake> listB) {
List<Cake> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
如果您想要 return Cake
的某些常见子类型的选项,您可以将通配符与通用参数结合使用:
public static <T extends Cake> List<T> union(List<? extends T> listA, List<? extends T> listB) {
List<T> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
您现有的代码只能合并两个完全相同类型的列表。但是,您可以将类型签名(其余代码保持不变)更改为
public static <T extends Cake> List<T> union(
List<? extends T> listA, List<? extends T> listB
)
在这种情况下,您是说这两个列表可以是任何类型,只要该类型是 T
的子类型,T
是 Cake
的子类型。
package cake;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static List<Cake> unionB(List<Cake> listA, List<Cake> listB) {
List<Cake> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
public static List<Cake> unionC(List<ChocolateCake> listA, List<VanillaCake> listB) {
List<Cake> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
public static List<Cake> unionD(List<? extends Cake> listA, List<? extends Cake> listB) {
List<Cake> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
public static void setB() {
List<Cake> a = new ArrayList<>();
a.add(new ChocolateCake());
List<Cake> b = new ArrayList<>();
b.add(new VanillaCake());
unionB(a, b);
}
public static void setC() {
List<ChocolateCake> a = new ArrayList<>();
a.add(new ChocolateCake());
List<VanillaCake> b = new ArrayList<>();
b.add(new VanillaCake());
unionC(a, b);
}
public static void setD() {
List<ChocolateCake> a = new ArrayList<>();
a.add(new ChocolateCake());
List<VanillaCake> b = new ArrayList<>();
b.add(new VanillaCake());
unionD(a, b);
}
}
这三种方法也行。
- unionB, unionC, unionD 参数类型取决于你的真实参数,当我们需要像
? extends T
这样的类型时,一般会有一个容器,容器需要保持不同的类型继承自T。在这种情况下, T是蛋糕。
? extends T
容器无法更新,所以你的第二种方法会导致编译错误。
- 您将三个方法 return 类型更改为 List
设想以下 class 层次结构:
Cake
\- ChocolateCake
\- StuffedChocolateCake
\- VanillaCake
我想写一个方法来组合 ChocolateCake 和 VanillaCake 的列表,例如:
public static <T extends Cake> List<T> union(List<T> listA, List<T> listB) {
List<T> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
这会抛出一个编译错误,我的理解是:
inferred type does not conform to equality constraint(s)
我尝试通过以下方式删除等式约束:
public static List<? extends Cake> union(List<? extends Cake> listA, List<? extends Cake> listB) {
List<? extends Cake> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
我想这是 Java 泛型的一个相当基本的场景,正确的方法是什么?
提前感谢您的宝贵时间!
将 return 类型更改为 List<Cake>
,您的第二个版本应该可以正常工作:
public static List<Cake> union(List<? extends Cake> listA, List<? extends Cake> listB) {
List<Cake> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
如果您想要 return Cake
的某些常见子类型的选项,您可以将通配符与通用参数结合使用:
public static <T extends Cake> List<T> union(List<? extends T> listA, List<? extends T> listB) {
List<T> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
您现有的代码只能合并两个完全相同类型的列表。但是,您可以将类型签名(其余代码保持不变)更改为
public static <T extends Cake> List<T> union(
List<? extends T> listA, List<? extends T> listB
)
在这种情况下,您是说这两个列表可以是任何类型,只要该类型是 T
的子类型,T
是 Cake
的子类型。
package cake;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static List<Cake> unionB(List<Cake> listA, List<Cake> listB) {
List<Cake> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
public static List<Cake> unionC(List<ChocolateCake> listA, List<VanillaCake> listB) {
List<Cake> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
public static List<Cake> unionD(List<? extends Cake> listA, List<? extends Cake> listB) {
List<Cake> returnObject = new ArrayList<>();
returnObject.addAll(listA);
returnObject.addAll(listB);
return returnObject;
}
public static void setB() {
List<Cake> a = new ArrayList<>();
a.add(new ChocolateCake());
List<Cake> b = new ArrayList<>();
b.add(new VanillaCake());
unionB(a, b);
}
public static void setC() {
List<ChocolateCake> a = new ArrayList<>();
a.add(new ChocolateCake());
List<VanillaCake> b = new ArrayList<>();
b.add(new VanillaCake());
unionC(a, b);
}
public static void setD() {
List<ChocolateCake> a = new ArrayList<>();
a.add(new ChocolateCake());
List<VanillaCake> b = new ArrayList<>();
b.add(new VanillaCake());
unionD(a, b);
}
}
这三种方法也行。
- unionB, unionC, unionD 参数类型取决于你的真实参数,当我们需要像
? extends T
这样的类型时,一般会有一个容器,容器需要保持不同的类型继承自T。在这种情况下, T是蛋糕。 ? extends T
容器无法更新,所以你的第二种方法会导致编译错误。- 您将三个方法 return 类型更改为 List