2011-01-24 5 views
5

私はJavaで1つのメソッドadd()をコーディングしたいと思います。それは整数、文字列などを追加することができます。ジェネリックスが私を助けます。ジェネリックスがJavaである理由オーバーロードとはどのように違うのですか?

Genericsの最終的な目的を理解できませんでした。私はとても混乱しています。

Generics vs Overloading?

public Integer add(Integer i, Integer j){return i+j;} 
public String add(String i, String j){return i+j;} 
public <T> T add(T i, T j){return i+j;} //this gives me error. 

私をそこから取り除いてください。

ありがとうございました。

+1

「整数i +整数j」を実行すると、実際には「整数」が追加されていません。 'Integers'は' + '演算子をサポートしていません。それらは 'ints'にunboxされ、' Integer'オブジェクトとして直接追加されることはありません。オブジェクトは '+'演算子をサポートしていないので、汎用オブジェクトを追加することはできません。 'Strings'は特殊なケースで、' + 'をサポートします。 –

+4

あなたが両方の例を 'add'と呼ぶ唯一の理由は、' + '演算子を使うからです。これは実際には意味のない類似点です。呼び出し元の視点から実際に何をするかに基づいた名前付けメソッド - この場合は 'sum'と' concatenate'は良い名前になります。 –

答えて

4

Javaでadd()メソッドをコーディングして、整数や文字列などを追加できます。ジェネリックスが役に立ちます。

NO

ジェネリック医薬品は、主に、コンパイル時に型の安全性のために使用されています。

あなたが

  • Generics
  • のみ、文字列のないスーパークラスが何もサブクラス[例えばが存在しない場合]

    List<String> lst;

    がStringを受け入れるコレクションに追加するには、一種類のみを指定することができます

+1

'はStringのみを受け付け、Stringのスーパークラスはサブクラスなし' - それは当てはまりません。 'void add42(List list){list.add(42);}'のようなものは完全に有効です。 – maaartinus

5

ジェネリックスヘルプ、ここでの問題は、+オペレーションがJavaプリミティブとStringに対してのみ定義されていますが、一般的な型に対しては定義されていないことです。 Javaでは、演算子をオーバーロードすることはできません(たとえば、C++のように)。ジェネリックなし

現実的な解決策は次のようになります。

public Integer add(Integer a, Integer b) { return a + b; } // sum of a and b 
public String add(String a, String b) { return a + b; }  // concatenate operation! 
public MyType add(MyType a, MyType b) { return a.add(b); } // requires add operation 
+2

2番目の段落は真ではありません。戻り値の型はJavaのメソッドシグネチャの一部ではなく、名前とパラメータの型だけです。パラメータが異なる場合は、異なる戻り値の型を持つことができます。あるいは、あなたが書いたことを誤解しましたか? –

+0

戻り値の型でオーバーロードが決定されません。オーバーロードの場合、戻り値の型は同じである必要はありません。 – Manoj

+0

@Jonathan - ありがとうございました - 典型的なShortOnCoffeeErrorでした:-)回答は予約済みの別の "Java for Beginners"コースに変更しました;) –

2

ジェネリック適切に行われれば、それはあなたが書いたコードの一部を一般化することができますので、いいです。ソフトウェアの作成に関しては、不要なコードを最小限に抑え、可能な限り多くのコードを再利用したいと考えています。

オーバーロードのアプローチを使用すると、オーバーロードのそれぞれを書き出す必要がありますが、ジェネリックでは一度だけ行う必要があります。ジェネリックスは、一連のコレクションに対して特定の一般的な操作を実行するため、コレクションを操作する状況でうまく機能します。いくつかの状況を処理するために、よりカスタマイズされたアプローチを望む場合は、メソッドをオーバーロードする必要がありますが、複数の場所で使用できる場合はジェネリックを記述することを目標にしています。

+0

私はJava GenericsとC++テンプレートを混同しています。ジェネリックスとテンプレートを比較するためのリンクがあれば、私にはもっと役立ちます。 – Manoj

+1

http://stackoverflow.com/questions/36347/what-are-the-differences-between-generic-types-in-c-and-javaこの2つの類似点と相違点を理解するのに役立ちます。 –

1

これはまさにジェネリックの要点です。 すべてを受け入れることができる1つのメソッドを実装する必要はありません。率直に言ってあなたはいつもの方法

add(Object obj)

を実装し、それに渡す整数、文字列、ブール...しかし、ほとんどの場合、あなたはこれまでにしたくないことができます話します。このメソッドは引数を処理する必要があるため、パラメータの型を知っている必要があります。このような方法は、単に存在しません:

add(String s); 
add(int i); 

今あなたが追加するブール値を送信することはできません()メソッド:これは文字列を受け取り、整数2つのメソッドを実装する方法の追加を行いたい場合は、その理由です。

あなたはまた、一般的な方法

<T> void add(T arg);

を実装し、それを呼び出すことができます。this.<String>add("hello");またはthis.<Integer>add(123);

コンパイルエラーが発生しthis.<String>add(123);この場合。

3
public Integer add(Integer i, Integer j){return i+j;} 
public String add(String i, String j){return i+j;} 
public <T> T add(T i, T j){return i+j;} //this gives me error. 

この方法はほぼ同じように見えますが、この場合ジェネリックは手助けできません。これを考慮してください:

public <T> T add(T i, T j){return i+j;} 
... 
add(new Object(), new Object()); 

普通のObjectを一緒に追加するとはどういう意味ですか?いいえ、+Objectではサポートされていません。Tの代わりに使用できる他の多くのタイプではサポートされていません。一般的な方法<T> T add(T i, T j)を作成するには

は、一般的な方法は、効果的にあなたがObjectで行うことができる唯一のことを意味ジェネリック型パラメータT、上で許可されている方法や操作に制限されています。メソッド/操作+を使用しようとしています。ではなく、Objectで何かできることがあります。

一般的なメソッド本体で使用するすべてのメソッドと操作をサポートする共通基底クラスStringIntegerを見つけることで、この問題を解決することができます。 +演算子をサポートし、このような共通の基底クラスXXXXXがあったならば、我々はこれを行うことができます:

public <T extends XXXXX> T add(T i, T j) { return i+j; } 

しかし、私たちがやりたいすべてのものをサポートしています共通の基底クラスXXXXXはありませんジェネリックメソッド(+)ですので、ジェネリックはこの問題を解決するために使用できません。

+1

'extended'に言及してくれてありがとうございました。 –

1

どのように汎用的なインタフェースを備えたアプローチについて:

interface Adder<T> { 
    T add(T first, T second); 
} 

そして、マネージャークラス:

public class AdderManager{ 

    public <T> AdderManager putAdder(final Class<T> clazz, 
     final Adder<? extends T> adder){ 
     adders.put(clazz, adder); 
     return this; 
    } 

    @SuppressWarnings("unchecked") 
    public <T> Adder<T> getAdder(final Class<T> clazz){ 
     return (Adder<T>) adders.get(clazz); 
    } 

    private final Map<Class<?>, Adder<?>> adders = 
     new HashMap<Class<?>, Adder<?>>(); 

} 

今、あなたは異なるクラスのカスタム加算器を登録して使用することができます。

final AdderManager manager = new AdderManager(); 
manager 
.putAdder(String.class, new Adder<String>(){ 

    @Override 
    public String add(final String first, final String second){ 
     return first.concat(second); 
    } 
}) 
.putAdder(Integer.class, new Adder<Integer>(){ 

    @Override 
    public Integer add(final Integer first, final Integer second){ 
     return first + second; 
    } 
}) 
.putAdder(List.class, new Adder<List<?>>(){ 

    @Override 
    public List<?> add(final List<?> first, final List<?> second){ 
     final List<Object> newList = new ArrayList<Object>(); 

     return newList; 
     } 
}); 

そして、このような加算器を使うことができます:

String addedString = manager.getAdder(String.class).add("abc", "def"); 

@SuppressWarnings("unchecked") // this is necessary because of 
           // the generic <Integer> type 
List<Integer> addedList = manager 
          .getAdder(List.class) 
          .add(
           Arrays.asList(1,2,3), 
           Arrays.asList(4,5,6) 
          ); 
1

Javaのジェネリックは、バイトコードにキャストするだけです。

キャスティングを除いて、コードは同じになります。

ように、2つの構造:

List list1 = new ArrayList(); 
List<String list2 = new ArrayList<String>(); 
.... 
String string1 = (String) list1.get(0); 
String string2 = list2.get(0); 

は同じことをやっています。

5

これがなぜ機能しないのか他の人が指摘しています。私はちょうど追加してみましょう、私はあなたが誤解していると思うJavaのジェネリックスは何です。おそらく、C++のテンプレートやCのマクロ展開に精通しているかもしれません。どちらもジェネリックに似ていますが、非常に異なるものです。

ジェネリックスは実際に型の安全性に関するもので、乱雑なキャストを避けるためのものです。特定のコレクションにStringが含まれていることをコンパイラーに伝え、入れたり取り出したりするすべてがStringでなければならないことを認識します。コンパイル時にあなたが入れたものをチェックし、取り出したものにいくつかのキャストを保存します。

コンパイラがタイプによって異なるコードを生成することはありません。ジェネリックスは、マクロやC++テンプレートのように、同じ関数の "int"バージョンと "float"バージョンの両方を書く必要を回避する簡単な方法ではありません。同じ機能を実装する2つのクラスを持っていても1つはintを使用し、もう1つは浮動小数点を使用することによって、望ましい動作を得ることができます。しかし、ジェネリックスを使わずにオブジェクト指向のテクニックでそれを実現できます。 「非ジェネリック」オブジェクト指向テクニックを使用して、必要な別個の動作を得ることができない場合は、ジェネリックスでも行うことはできません。

関連する問題