2011-09-10 10 views
0

Javaでは、2つの整数のリストを取り、2番目のリストに基づいて最初のリストから整数の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を新しいリストに適切なデータ型で再構築することを私に要求しています。これは高価です。さらに注意深く、単体テストを使用することから、コンパイラに2つのリストを区別させるための方法はありますか?

ScalaやHaskellなどの他の言語では、コピーせずに安全に再作成できるものがありますか?あなたの質問は簡単ではありません

+1

Btw。より良いデザインのためには、ArrayListではなくListインターフェイスを使用したいと考えています。また、おそらくList <? BInteger>を拡張します。 –

+0

こんにちは!だから、私は発見した私は、一般的な宣言に使用している場合 公共一覧 FUNC(一覧 A、一覧コンパイラがエラーをキャッチし、これは実行可能なソリューションである、またはオリジナルを行い B これは解決策として除外されていますか? – archgoon

答えて

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)は使用できません。新しいオブジェクトが作成されないようにします。したがって、結果のエクスポートされたリストには、元のリストの要素のみが含まれます(ダウンキャストが実行されない限り、すべての型保証は無効になります)。

1

、のようなものを試してください:

は、Javaでのあなたのために、「同等」とコンバーチブル異なるオブジェクトタイプ(リスト項目を入力します)が、2つのリストを受信し、返されたリストは、あなたが欲しいタイプが含まれていますアイテムを取得し、他のリストからの取得を避けます。

たとえば、public ArrayList<Integer> func(ArrayList<Integer> A, ArrayList<Number> B)を使用すると、ダウンキャストを明示的に実行する必要があるため、Bから返されたリストにアイテムをコピーできなくなります。 int項目やB項目が本当にintである場合は、Number.intValue()を呼び出して、B項目を数値として評価することができます。メソッド定義に@SupressWarningを入れないよう警告が出るジェネリックで明示的キャストを実行する必要があるため、Bが実際にArrayList<Integer>と定義されている場合は問題です。

もう1つの質問は、Javaでコンパイルするときにジェネリック型が "消去"されるため、実行時の汎用型チェックを防ぐType Erasureです。 C#in .Netは型消去を持たず、実行時にコレクションの型を保証します(例えば)。

1

実際、C++には私的継承という機能があります。親のすべての機能が継承されるようにクラスで動作しますが、ユーザーはそれを共通の親として扱うことはできません。残念ながら、これはプリミティブでは機能しません。

Javaは、このような機能をサポートしていません。ほとんどの言語は、この種の「意味的差別化」を簡単な方法でサポートしていません。両方のクラスに対して生成されるコードは等しくなることに注意してください。私はあなたがJavaであなたがやりたいことができるとは思わないものの

0

は、あなたが問題を回避するためにあなたの方法を少しリファクタリングすることができます

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); 
0

あなたは次のように変更にする方が良いでしょう:

  • タイプ戻り値の型、あなたの方法は、任意のインスタンスフィールドのアクセスを必要としないので、あなたが安全にあなたが行うことができます、方法staticを作る
  • それに整数を追加できるように - それだけで「コード」
  • です
  • はあなたのパラメータを宣言し、抽象種類使用して型を返す - 誰かが例えばLinkedListに渡したいことがあるので、すなわちListではなく、具体的なタイプArrayListを - あなたのコードだけではなくArrayList
  • 、すべてのリストタイプに適用されます
  • 有力小文字を使用して、変数に名前を付けて - それはあなたのコードこのような、より快適に

読むことができるので、他のいつものスタイルは以下:

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、Integerfinalクラスです。あなたがこれを行うことはできませんので、あなたは、それを拡張することはできません:ジェネリックを使用することによりclass AInteger extends Integer

+0

'final'については良い点がありますが、 ' ' をテンプレートパラメータとして使用できます。 – archgoon

関連する問題