2011-02-07 7 views
2

インタフェースを使用してサービスのタイプを参照する単一のクラスを作成したいとします。サービスは異なる実装を持つことができます。異なる実装は、異なるタイプの要求を処理します。過去には私はこのようなインタフェース何かを定義します:ジェネリックを使用する再利用可能なインタフェース

public interface I_Test 
{ 
    public String get(String key, Enum type); 
} 

をし、このようにそれを実装:

public class Test_1 implements I_Test 
{ 
    public String get(String key, Enum type) 
    { 
     Enum_1 t1 = (Enum_1)type; 

     switch(t1) 
     { 
      case NAME: 
       return "Garry"; 
      case DOB: 
       return "1966"; 
      default: 
       throw new IllegalArgumentException("Unkown type [" + type + "]"); 
     } 
    } 
} 

良い、私はさまざまなニーズを満たすために私のインタフェースの異なる実装を使用することができます。 悪いですが、キャストを打つ必要があり、実行時にリスクがあります。

私はジェネリックがこれを解決することができることを期待していたので、私はこれでした:

public interface I_Test<T extends Enum> 
{ 
    public String get(String key, T type); 
} 

と、この:

public class Test_1 implements I_Test<Enum_1> 
{ 
    public String get(String key, Enum_1 type) 
    { 
     switch(type) 
     { 
      case NAME: 
       return "Garry"; 
      case DOB: 
       return "1966"; 
      default: 
       throw new IllegalArgumentException("Unkown type [" + type + "]"); 
     } 
    } 
} 

が、私はものを使用することを行くとき、私は私ない限り、型の安全性の警告を取得します私が使用しようとしているタイプの変数を宣言してください:

I_Test<Enum_1> t1 = new Test_1(); 

これは本当に私にはバグですI_Testインターフェイスを作成するためのポイントは、さまざまな実装を使用できるようになっていましたが、この警告を避けるためにコンパイル時に特定のタイプにロックする必要があるようです。

この迷惑な警告なしにジェネリックを使用する再利用可能なインターフェイスを作成する方法はありますか?

+0

私は本当にあなたのインターフェースが何をするのか理解していないが、それはインターフェースの誤用のように見えます(それがどのような文脈では、「要求の種類を処理するために、」何を意味するのでしょうか) - 主に実装理由多型の代わりに 'switch'を使います。 'Map ' – davin

+0

で上記のロジックがはるかに簡単にできるように見えます。私は機密データを削除しなければなりませんでした。私が言うことは、getはデータと要求のタイプを取ることです。リクエストのタイプは実装依存です。現在、サポートされている実装は4つあります。また、私が働いている場所には30種類以上のリクエストがあります。 – BigMac66

答えて

4

ジェネリックのポイントは、コードの信頼性を保証することです(タイプセーフに関する限り)。ジェネリックでは、実行時ではなくコンパイル時に型の非互換性を知ることができます。インターフェイスをI_Test<T extends Enum>と定義した場合、基本的にはとなります。には、特定のタイプに従って汎用化されるインターフェイスが必要です。これがJavaがあなたに警告を出す理由です。

このような場合は、Map myMap = new HashMap<string>();と同じ警告が表示されます。

Javaでは、実際には型を指定します(Integer i = 1のようなことをしない限り、型はRHS上から推測されませんが、オートボクシングです)。インターフェイスを汎用化したので、そのインターフェイスを使用して何かを宣言するときは、(汎用化するために)使用するタイプを指定する必要があります。

ジェネリック型をインスタンス化すると、コンパイラは「型消去」と呼ばれるものを使用してこれらの型を変換します。ここでは、コンパイラは型パラメータと型引数に関連するすべての情報を削除します。 Javaは、Javaがジェネリックになる前に書かれた古いコードとの互換性を維持するためにこれを行います。

したがってI_Test<Enum_1>は、実際にはコンパイル時にRAWタイプI_Testに変換されます。生の型を使用することは、一般的に悪い習慣とみなされます(したがって、 "迷惑な警告")。コンパイラは、型チェックを実行するのに十分な情報がないため、型の安全性を確保できないことを伝えています(生の型を使用したため)。

次を見て、ジェネリックについて詳しく知ることができます。

+0

ご意見ありがとうございます。私は実際にあなたが言ったことのほとんどに精通しています。私は警告を避けることができないという賢明な方法を見つけようとしています。一般的な規則として、警告は有効な目的を果たし、抑制することを好まないと思います。これはそのルールの例外かもしれません::) – BigMac66

+0

あなたのインターフェース/クラスがジェネリックを使用している場合、警告を抑制する方法はありません。生の型を使用すると、あなたは*得るでしょう:)。警告を無視する必要があるのは、タイプ*が*あなたが期待するタイプ*であることを保証できるかどうかだけです。つまり、それが他のタイプであることが不可能な場合*です。 –

+0

ああ、それは私の問題です。なぜ私はジェネリックスに目を向けるのですか?私はシニア開発者であり、経験の浅い開発者の中には混在すべきでないものを混在させているものもあります。彼らはコードを再利用しようとしていると思っていますが、注意を払っていません。これはその問題に対する確かな解決策ではありませんが、ジェネリック医薬品を採用するのに十分な場合に役立つだろうと思います...あなたの助けをもう一度ありがとう。 – BigMac66

1

ジェネリックさは約時の警告をコンパイルです。あなたがそれらを必要としない場合、それらを使用しないでください。

により、たとえば、異なる、非ジェネリックサブインターフェイスを作成することができることを言った:

public interface Enum_1_Test extends I_Test<Enum_1> { 
    ... 
} 

をそして

public class Test_1 implements Enum_1_Test 

として、あなたのクラスを宣言しかし、私は、これは非常にある確信していません有用。大まかには、多くの入力タイプで動作する1つの実装を持つ場合はジェネリックを使用し、各入力タイプでは別々の実装をしたい場合は古いポリモーフィズムを使用します。

1

生のI_Testは任意の列挙型を引数としてサポートしますが、Test_1実装では限定サブセット(Enum_1)しかサポートしません。これはTest_1が1つの列挙型に対してのみI_Testを実装するためです。

ここでは、コンパイラが警告を発行する例を示します。次のコードは、I_Testの生の型が任意の列挙型を受け入れるためコンパイルしますが、Test_1はEnum_1しかサポートしないため、クラスキャスト例外が発生します。

enum MyEnum{A} 
I_Test t1 = new Test_1();//warning here 
t1.get("",MyEnum.A);//Exception at runtime, but compiles fine 

ジェネリック型を指定すると、コンパイルエラーが発生します。これは実行時の例外よりも優先されます。

enum MyEnum{A} 
I_Test<Enum_1> t1 = new Test_1(); 
t1.get("",MyEnum.A);//Does not compile 
関連する問題