在Java中,假设我有一个方法,它接收两个整数列表,并根据第二个列表从第一个列表返回一个整数的arrayList。
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;
}
现在假设我做了一些愚蠢的事情,比如将插入更改为
result.add(b.get(i));
如果我可以做类似
的事情,那就太好了public ArrayList<AInteger> func(ArrayList<AInteger> A, ArrayList<BInteger> B)
确保无论睡眠不足,编译器都会阻止我犯这种错误。现在我们可以试试
class AInteger extends Integer{}; class BInteger extends BInteger{};
并使用
调用方法func((ArrayList<AInteger>) A, (ArrayList<BInteger>) B);
不幸的是,向下转换会引发运行时异常。因此,这个解决方案需要我(我认为)将A和B重建为具有适当数据类型的新列表,这很昂贵。除了更加小心,并使用单元测试之外,还有什么方法可以让编译器区分这两个列表?
Scala或Haskell等其他语言是否提供了允许我安全重铸而无需复制的东西?
答案 0 :(得分:1)
你的问题并不容易,请尝试以下方法:
接收两个具有不同对象类型的列表(列表项类型),但是对于您来说是“等效”并且可以在Java中转换,并且返回的列表包含您要从中获取项目的类型,从而避免从其他列表中获取。
例如,使用public ArrayList<Integer> func(ArrayList<Integer> A, ArrayList<Number> B)
这可以防止您将项目从B复制到返回列表,因为您需要明确执行向下转换。如果您想要整数和/或B项真的是整数,您仍然可以通过调用Number.intValue()
来评估B项目作为数字。如果B实际定义为ArrayList<Integer>
,则问题是调用,因为您需要使用泛型执行显式强制转换,从而引发警告,避免将@SupressWarning
放入方法定义中。
另一个问题是Type Erasure在运行时阻止泛型类型检查,因为在Java中编译时,泛型类型被“擦除”。 .Net中的C#没有类型擦除,并且在运行时保证集合的类型(例如)。
答案 1 :(得分:1)
实际上C ++有一个称为私有继承的功能。它适用于类,以便继承父级的所有功能,但用户不能将其视为公共父级。不幸的是,这不适用于原语。
Java不支持这样的功能。大多数语言都不直接支持这种“语义区分”。请记住,为两个类生成的代码都是相同的。
答案 2 :(得分:0)
虽然我认为你不能在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);
答案 3 :(得分:0)
您最好进行以下更改:
static
,您可以这样做,因为您的方法不需要访问任何实例字段 - 它只是“代码”List
,而不是具体类型ArrayList
,因为有人可能想要传递LinkedList
例如 - 您的代码适用于所有列表类型,而不仅仅是ArrayList
s 像这样:
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;
}
此代码允许您使用替代代码result.add(b.get(i))
。
BTW,Integer
是final
类;你不能扩展它,所以你不能这样做:class AInteger extends Integer
答案 4 :(得分:0)
通过使用泛型,可以通过将函数声明修改为
来解决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;
}
这可确保result.add(B.get(i))
根据需要引发类型错误。
不幸的是......不允许使用新的IntegerA(int),这会阻止创建新对象。因此,导出的导出列表只能包含原始列表中的元素(除非执行向下转换,这会使任何类型保证无效)。