Java 区分等价数据类型
在Java中,假设我有一个方法,它接受两个整数列表,并基于第二个列表从第一个列表返回一个整数数组列表Java 区分等价数据类型,java,types,Java,Types,在Java中,假设我有一个方法,它接受两个整数列表,并基于第二个列表从第一个列表返回一个整数数组列表 public ArrayList<Integer> func(ArrayList<Integer> A, ArrayList<Integer> B){ ArrayList result = new ArrayList(); //A and B have the same length for(int index = 0; index <
public ArrayList<Integer> func(ArrayList<Integer> A, ArrayList<Integer> B){
ArrayList result = new ArrayList();
//A and B have the same length
for(int index = 0; index < A.length();index++){
//Decide if a gets added to result based on the corresponding B
if(decisionFunction(B.get(i)){
result.add(a.get(i));
}
}
return result;
}
如果我能像这样做就好了
public ArrayList<AInteger> func(ArrayList<AInteger> A, ArrayList<BInteger> B)
并使用
func((ArrayList<AInteger>) A, (ArrayList<BInteger>) B);
func((ArrayList)A,(ArrayList)B);
不幸的是,向下广播将引发运行时异常。所以,这个解决方案需要我(我认为)用合适的数据类型将A和B重新构建成新的列表,这是非常昂贵的。除了更加小心和使用单元测试之外,还有什么方法可以让编译器区分这两个列表吗
其他语言(如Scala或Haskell)是否提供了无需复制即可安全重铸的功能?您的问题并不简单,请尝试以下方法: 接收两个具有不同对象类型(list items类型)但在Java中“等效”且可转换的列表,返回的列表包含要从中获取项目的类型,避免从其他列表获取项目 例如,使用
public ArrayList func(ArrayList A,ArrayList B)
这可以防止您将项目从B转到返回列表,因为您需要显式执行向下转换。如果您想要整数和/或B项实际上是整数,您仍然可以通过调用Number.intValue()
将B项计算为数字。问题在于,如果B真的被定义为ArrayList
,那么调用就会出现问题,因为您需要使用泛型执行显式强制转换,该泛型会引发警告,从而避免将@superswarning
放入方法定义中
另一个问题是,在运行时防止泛型类型检查,因为在Java中编译时泛型类型被“擦除”。.NET中的C++不具有类型擦除,并在运行时保证集合的类型(例如)。< P>实际上C++具有一个称为私有继承的特性。它与类一起工作,以便继承父级的所有功能,但用户不能将其视为公共父级。不幸的是,这不适用于原语
Java不支持这样的特性。大多数语言都不直接支持这种“语义差异”。请记住,为这两个类生成的代码是相等的。虽然我认为您不能在Java中随心所欲,但您可以稍微重构您的方法以避免问题:
void func(ArrayList<Integer> B /* input only */ ,
ArrayList<Integer> A /* input-output */) {
// remove some elements from A as necessary
}
...
ArrayList<Integer> result = new ArrayList<Integer>();
result.addAll(A);
func(B, result);
void func(ArrayList B/*仅限输入*/,
ArrayList A/*输入输出*/){
//如有必要,从中删除一些元素
}
...
ArrayList结果=新建ArrayList();
结果:addAll(A);
func(B,结果);
您最好进行以下更改:
- 键入返回类型,以便可以安全地向其添加整数
- 使方法成为静态的,因为你的方法不需要访问任何实例字段——它只是“代码”
- 使用抽象类型(即
)而不是具体类型List
)声明参数和返回类型,因为有人可能希望传入ArrayList
,例如,您的代码应用于所有列表类型,而不仅仅是LinkedList
sArrayList
- 用前导小写字母命名变量-它遵循通常的样式,这样其他人可以更轻松地阅读您的代码
public static List<Integer> func(List<Integer> a, List<Integer> b) {
List<Integer> result = new ArrayList<Integer>();
for (int index = 0; index < a.length(); index++) {
if (decisionFunction(b.get(i)) {
result.add(a.get(i));
}
}
return result;
}
公共静态列表函数(列表a、列表b){
列表结果=新建ArrayList();
对于(int index=0;index
此代码将允许您的可选代码结果。添加(b.get(i))
工作
顺便说一句,
Integer
是一个final
类;您不能扩展它,所以您不能这样做:class AInteger使用泛型扩展Integer
,这可以通过修改要扩展的函数声明来解决
public <IntegerA extends Integer, IntegerB extends Integer>
List<IntegerA> func(List<IntegerA> A, List<IntegerB> B){
ArrayList result = new ArrayList();
//A and B have the same length
for(int index = 0; index < A.length();index++){
//Decide if a gets added to result based on the corresponding B
if(decisionFunction(B.get(i)){
result.add(A.get(i));
}
}
return result;
}
公共
列表功能(列表A、列表B){
ArrayList结果=新建ArrayList();
//A和B的长度相同
对于(int index=0;index
这确保result.add(B.get(i))
根据需要引发类型错误
不幸的是,不允许使用新的整数(int),这会阻止创建新对象。因此,生成的导出列表只能包含原始列表中的元素(除非执行向下转换,这会使任何类型保证无效).顺便说一句。为了更好地设计,您希望使用列表接口,而不是ArrayList。此外,您可能希望使用ListHi!因此,我发现如果使用泛型声明public List funct(列表A,列表B编译器捕捉到错误。这是一个可行的解决方案,还是原始问题陈述排除了这一解决方案?关于
final
的观点很好。但是,您仍然可以将
作为模板参数。
public static List<Integer> func(List<Integer> a, List<Integer> b) {
List<Integer> result = new ArrayList<Integer>();
for (int index = 0; index < a.length(); index++) {
if (decisionFunction(b.get(i)) {
result.add(a.get(i));
}
}
return result;
}
public <IntegerA extends Integer, IntegerB extends Integer>
List<IntegerA> func(List<IntegerA> A, List<IntegerB> B){
ArrayList result = new ArrayList();
//A and B have the same length
for(int index = 0; index < A.length();index++){
//Decide if a gets added to result based on the corresponding B
if(decisionFunction(B.get(i)){
result.add(A.get(i));
}
}
return result;
}