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 <

在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 < 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
    ,例如,您的代码应用于所有列表类型,而不仅仅是
    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;
}
公共静态列表函数(列表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;
}