web-dev-qa-db-ja.com

ジェネリックのクールな点、それらを使用する理由

私はこのソフトボールを公園の外に打ちたい人に提供すると思いました。ジェネリックとは何ですか、ジェネリックの利点は何ですか、なぜ、どこで、どのように使用すればよいですか?かなり基本的なものにしてください。ありがとう。

80
MrBoJangles
  • タイプセーフなコードを記述したり、ライブラリメソッドを使用したりできます。つまり、List <string>は文字列のリストであることが保証されています。
  • ジェネリックが使用された結果、コンパイラは型安全性のためにコードのコンパイル時チェックを実行できます。つまり、文字列のリストにintを入れようとしていますか? ArrayListを使用すると、透過性の低いランタイムエラーが発生します。
  • オブジェクトを使用するよりも、ボックス化/ボックス化解除(.netが 値型を参照型に、またはその逆 に変換する必要がある)またはオブジェクトから必要な参照型にキャストするよりも高速です.
  • 同じ基礎となる多くの型に適用可能なコードを記述できます。つまり、Dictionary <string、int>は、Dictionary <DateTime、double>と同じ基礎コードを使用します。ジェネリックを使用すると、フレームワークチームは、前述の利点を備えた両方の結果を達成するために1つのコードを記述するだけで済みました。
120
ljs

繰り返すのは本当に嫌いです。同じことを頻繁に入力するのは嫌いです。わずかな違いがあるものを何度も書き直すのは好きではない。

作成する代わりに:

class MyObjectList  {
   MyObject get(int index) {...}
}
class MyOtherObjectList  {
   MyOtherObject get(int index) {...}
}
class AnotherObjectList  {
   AnotherObject get(int index) {...}
}

再利用可能なクラスを1つ作成できます...(何らかの理由で生のコレクションを使用したくない場合)

class MyList<T> {
   T get(int index) { ... }
}

効率が3倍になり、1つのコピーを維持するだけで済みます。なぜあなたはより少ないコードを維持したいのですか?

これは、他のクラスと対話する必要があるCallable<T>Reference<T>などの非コレクションクラスにも当てはまります。本当にCallable<T>Future<T>および他のすべての関連クラスを拡張して、タイプセーフバージョンを作成しますか?

しません。

46
James Schek

タイプキャストする必要がないことは、Java generics)の最大の利点の1つです。これにより、実行時にスローされる可能性のあるClassCastExceptionsの可能性が減り、より堅牢なコードにつながる可能性があります。

しかし、あなたはそれを完全に知っていると思います。

Genericsを見るたびに頭痛がします。 Javaの最良の部分は、単純であり、最小限の構文とジェネリックは単純ではなく、かなりの量の新しい構文を追加することです。

最初は、ジェネリック医薬品の利点もわかりませんでした。私は1.4構文からJavaを学び始めました(Java 5が当時出ていたとしても))、ジェネリックに遭遇したとき、それはより多くのコードであると感じました書くために、私は本当に利点を理解していませんでした。

最新のIDEを使用すると、ジェネリックでコードを記述しやすくなります。

最新のまともなIDEは、特にコード補完に関して、ジェネリックを使用したコードの記述を支援するのに十分なほどスマートです。

HashMapを使用してMap<String, Integer>を作成する例を次に示します。入力する必要があるコードは次のとおりです。

Map<String, Integer> m = new HashMap<String, Integer>();

そして実際、新しいHashMapを作成するためだけに入力するのはたくさんあります。ただし、実際には、Eclipseが必要なものを知る前に、これだけを入力する必要がありました。

Map<String, Integer> m = new Ha Ctrl+Space

確かに、候補のリストからHashMapを選択する必要がありましたが、基本的にIDEはジェネリック型を含む追加対象を知っていました。

さらに、型は既知であるため、ジェネリックコレクションから要素を取得する場合、IDEはそのオブジェクトが既に宣言された型のオブジェクトであるかのように動作します。キャストする必要はありません。 IDEの場合、オブジェクトのタイプを知るために。

ジェネリックの主な利点は、新しいJava 5つの機能でうまく機能する方法にあります。ここにトスの例を示しますSetへの整数とその合計の計算:

Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(42);

int total = 0;
for (int i : set) {
  total += i;
}

このコードには、3つの新しいJava 5つの機能があります。

まず、プリミティブのジェネリックおよびオートボクシングにより、次の行が許可されます。

set.add(10);
set.add(42);

整数10は、10の値を持つIntegerに自動ボックス化されます。 (42についても同じです)。次に、そのIntegerは、Setsを保持することが知られているIntegerに投げ込まれます。 Stringをスローしようとすると、コンパイルエラーが発生します。

次に、for-eachループはこれらの3つすべてを取ります。

for (int i : set) {
  total += i;
}

最初に、Setsを含むIntegerがfor-eachループで使用されます。各要素はintであると宣言されており、Integerがボックス化されてプリミティブintに戻されるため、許可されます。また、このアンボックス化が発生するという事実は、IntegerSetsが保持されていることを指定するためにジェネリックが使用されたためです。

ジェネリックは、Java 5で導入された新しい機能を統合する接着剤になることができます。また、コーディングがより簡単で安全になります。だから、一般的に、それ以上のタイピングはありません。

率直に言って、Setの例からわかるように、Java 5の機能を使用すると、コードがより簡潔で堅牢になります。

編集-ジェネリックなしの例

以下に、ジェネリックを使用しない上記のSetの例を示します。それは可能ですが、正確に快適ではありません:

Set set = new HashSet();
set.add(10);
set.add(42);

int total = 0;
for (Object o : set) {
  total += (Integer)o;
}

(注:上記のコードは、コンパイル時に未チェックの変換警告を生成します。)

非ジェネリックコレクションを使用する場合、コレクションに入力される型はObject型のオブジェクトです。したがって、この例では、Objectはセットにaddedされているものです。

set.add(10);
set.add(42);

上記の行では、オートボクシングが機能しています-プリミティブint value 10および42Integerオブジェクトにオートボックス化され、Setに追加されています。ただし、IntegerオブジェクトがObjectsとして処理されていることに注意してください。これは、Setが期待する型をコンパイラーが知るのに役立つ型情報がないためです。

for (Object o : set) {

これが重要な部分です。 for-eachループが機能する理由は、SetIterable インターフェイスを実装しているためです。このインターフェイスは、存在する場合、タイプ情報を含むIteratorを返します。 (Iterator<T>、つまり。)

ただし、型情報がないため、SetIteratorの値をSetsとして返すObjectを返します。これが、for-eachループで取得される要素mustの理由ですタイプObject

ObjectSetから取得されたので、追加を実行するには手動でIntegerにキャストする必要があります。

  total += (Integer)o;

ここで、タイプキャストはObjectからIntegerへ実行されます。この場合、これは常に機能することがわかっていますが、手動の型キャストを行うと、どこかで小さな変更が加えられた場合に破損する可能性がある壊れやすいコードであると常に感じます。 (すべてのタイプキャストはClassCastExceptionが起こるのを待っていると感じますが、私は脱線します...)

Integerは現在、intにアンボックス化され、int変数totalへの追加を実行できます。

Java 5の新しい機能は非ジェネリックコードでも使用可能ですが、ジェネリックでコードを書くほどクリーンで簡単ではありません。 、私の意見では、Java 5の新機能を最大限に活用するには、少なくともジェネリックを調べる必要があります。実行時に例外をスローします。

20
coobird

1.5がリリースされる直前にJavaバグデータベースを検索した場合、NullPointerExceptionのバグはClassCastExceptionより7倍多く見つかります。バグ、または少なくとも少しの煙のテストを行っても持続するバグを見つけるのは素晴らしい機能ではないようです。

私にとってジェネリックの大きな利点は、それらがコード内重要な型情報を文書化することです。その型情報をコードで文書化したくない場合は、動的に型付けされた言語、または少なくとも暗黙的な型推論を持つ言語を使用します。

オブジェクトのコレクションをそれ自体に保持することは悪いスタイルではありません(しかし、一般的なスタイルはカプセル化を事実上無視することです)。それはむしろあなたが何をしているかに依存します。コレクションを「アルゴリズム」に渡すと、ジェネリックを使用して(コンパイル時またはコンパイル前に)チェックするのが少し簡単になります。

15

Java= parametric polymorphism を容易にするジェネリック。型パラメータを使用すると、型に引数を渡すことができます。String foo(String s)のようなメソッドは、特定の文字列だけでなく、任意の文字列sの動作なので、List<T>は、特定の型だけでなく任意の型の動作をモデル化します。 List<T>は、すべてのタイプTには、エレメントがListsであるTのタイプがありますと言います。したがって、Listは、実際には型コンストラクタです。型を引数として受け取り、結果として別の型を作成します。

ここに、私が毎日使用するジェネリック型の例をいくつか示します。まず、非常に便利な汎用インターフェース:

public interface F<A, B> {
  public B f(A a);
}

このインターフェースは、ABの2つのタイプには、fを取り、Aを返す関数(Bと呼ばれる)があります。このインターフェースを実装すると、AB必要な、前者を取り、後者を返す関数fを提供する限り。インターフェイスの実装例を次に示します。

F<Integer, String> intToString = new F<Integer, String>() {
  public String f(int i) {
    return String.valueOf(i);
  }
}

ジェネリックの前は、extendsキーワードを使用してsubclassingによって多態性が達成されていました。ジェネリックを使用すると、実際にはサブクラス化を廃止し、代わりにパラメトリック多相性を使用できます。たとえば、あらゆるタイプのハッシュコードを計算するために使用されるパラメーター化された(汎用)クラスを考えてみましょう。 Object.hashCode()をオーバーライドする代わりに、次のような汎用クラスを使用します。

public final class Hash<A> {
  private final F<A, Integer> hashFunction;

  public Hash(final F<A, Integer> f) {
    this.hashFunction = f;
  }

  public int hash(A a) {
    return hashFunction.f(a);
  }
}

これは、継承を使用するよりもはるかに柔軟性があります。なぜなら、脆弱な階層をロックダウンすることなく、構成とパラメトリック多型を使用するというテーマにとどまることができるからです。

ただし、Javaのジェネリックは完全ではありません。タイプを抽象化することはできますが、たとえば、タイプコンストラクターを抽象化することはできません。つまり、「任意の型Tに対して」と言うことはできますが、「型パラメーターAを取る任意の型Tに対して」とは言えません。

Java generics、here。 のこれらの制限に関する記事を書きました。

ジェネリックの大きな利点の1つは、サブクラス化を回避できることです。サブクラス化は、拡張が困難な脆弱なクラス階層、および階層全体を見ずに個別に理解することが難しいクラスをもたらす傾向があります。

ジェネリックの前に、WidgetFooWidget、およびBarWidgetによって拡張されるBazWidgetのようなクラスがあり、ジェネリックでは単一のジェネリッククラスWidget<A>は、コンストラクタでFooBar、またはBazを使用して、Widget<Foo>Widget<Bar>、およびWidget<Baz>

10
Apocalisp

ジェネリックは、ボクシングとアンボクシングのパフォーマンスヒットを回避します。基本的に、ArrayListとList <T>を見てください。どちらも同じコア処理を行いますが、List <T>はオブジェクトとの間でボックス化する必要がないため、はるかに高速になります。

8
Darren Kopp
  • 型付きコレクション-使用したくない場合でも、他のライブラリ、他のソースからそれらを処理する必要があります。

  • クラス作成での一般的な型付け:

    パブリッククラスFoo <T> {public T get()...

  • キャストの回避-私はいつものようなものを嫌っていました

    新しいコンパレータ{public int compareTo(Object o){if(o instanceof classIcareAbout)...

インターフェースがオブジェクトの観点から表現されているためにのみ存在すべき条件を本質的にチェックしている場所。

ジェネリック医薬品に対する私の最初の反応は、あなたのものに似ていました-「面倒すぎる、複雑すぎる」。私の経験では、それらを少し使用した後は慣れてしまい、それらのないコードは明確に指定されていないと感じ、快適性が低下します。それとは別に、残りのJavaワールドはそれらを使用するので、最終的にプログラムを取得する必要がありますか?

5
Steve B.

良い例を挙げましょう。 Fooというクラスがあると想像してください

public class Foo
{
   public string Bar() { return "Bar"; }
}

例1ここで、Fooオブジェクトのコレクションが必要になります。 LIstまたはArrayListの2つのオプションがあり、どちらも同様に機能します。

Arraylist al = new ArrayList();
List<Foo> fl = new List<Foo>();

//code to add Foos
al.Add(new Foo());
f1.Add(new Foo());

上記のコードで、Fooの代わりにFireTruckのクラスを追加しようとすると、ArrayListが追加しますが、FooのGeneric Listは例外をスローします。

例2

これで、2つの配列リストがあり、それぞれに対してBar()関数を呼び出すことができます。 hte ArrayListはオブジェクトで満たされているため、barを呼び出す前にそれらをキャストする必要があります。ただし、Fooの汎用リストにはFoosのみを含めることができるため、それらに対して直接Bar()を呼び出すことができます。

foreach(object o in al)
{
    Foo f = (Foo)o;
    f.Bar();
}

foreach(Foo f in fl)
{
   f.Bar();
}
5
Peter Lange

カスタムタイプを簡単に定義する方法を提供してくれるので、とにかく気に入っています(とにかく使用しています)。

したがって、たとえば、文字列と整数で構成される構造を定義し、それらの構造の配列にアクセスする方法などのオブジェクトとメソッドのセット全体を実装する必要がある代わりに、単に辞書を作成することができます

Dictionary<int, string> dictionary = new Dictionary<int, string>();

そして、コンパイラ/ IDEが残りの面倒な作業を行います。特にディクショナリを使用すると、最初のタイプをキーとして使用できます(値の繰り返しはありません)。

5
Tom Kidd

Genericsの最大の利点は、コードの再利用です。多数のビジネスオブジェクトがあり、各エンティティに対して非常に類似したコードを記述して、同じアクションを実行するとします。 (I.E Linq to SQL操作)。

ジェネリックを使用すると、特定の基本クラスから継承する任意の型を指定して操作できる、または特定のインターフェイスを次のように実装できるクラスを作成できます。

public interface IEntity
{

}

public class Employee : IEntity
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int EmployeeID { get; set; }
}

public class Company : IEntity
{
    public string Name { get; set; }
    public string TaxID { get; set }
}

public class DataService<ENTITY, DATACONTEXT>
    where ENTITY : class, IEntity, new()
    where DATACONTEXT : DataContext, new()
{

    public void Create(List<ENTITY> entities)
    {
        using (DATACONTEXT db = new DATACONTEXT())
        {
            Table<ENTITY> table = db.GetTable<ENTITY>();

            foreach (ENTITY entity in entities)
                table.InsertOnSubmit (entity);

            db.SubmitChanges();
        }
    }
}

public class MyTest
{
    public void DoSomething()
    {
        var dataService = new DataService<Employee, MyDataContext>();
        dataService.Create(new Employee { FirstName = "Bob", LastName = "Smith", EmployeeID = 5 });
        var otherDataService = new DataService<Company, MyDataContext>();
            otherDataService.Create(new Company { Name = "ACME", TaxID = "123-111-2233" });

    }
}

上記のDoSomethingメソッドで異なるタイプを指定すると、同じサービスが再利用されることに注意してください。本当にエレガント!

あなたの仕事にジェネリックを使用する理由は他にもたくさんありますが、これが私のお気に入りです。

5
Dean Poulin

メソッド/クラスの重要な概念がパラメーター/インスタンス変数の特定のデータ型に厳密にバインドされていないメソッド(またはクラス)を書いたことはありませんか(リンクリスト、最大/最小関数、バイナリ検索を考えてください)など)。

カットアンドペーストの再利用やストロングタイピングを損なうことなく、アルゴリズム/コードを再利用できることを望んでいませんか(たとえば、ListではなくList物事Ihopeは文字列です!)?

そのため、ジェネリック(またはそれ以上のもの)を使用するにはwantを使用する必要があります。

4
Bert F

ジェネリックはクラスで使用されるだけでなく、メソッドでも使用できることを忘れないでください。たとえば、次のスニペットを使用します。

private <T extends Throwable> T logAndReturn(T t) {
    logThrowable(t); // some logging method that takes a Throwable
    return t;
}

シンプルですが、非常にエレガントに使用できます。良い点は、メソッドが与えられたものを返すことです。これは、呼び出し元に再スローする必要がある例外を処理するときに役立ちます。

    ...
} catch (MyException e) {
    throw logAndReturn(e);
}

重要なのは、型をメソッドに渡すことで型を失わないことです。単にThrowableの代わりに正しいタイプの例外をスローできます。これはジェネリックなしで実行できるすべてです。

これは、ジェネリックメソッドの1つの使用法の簡単な例です。ジェネリックメソッドでできることは他にもたくさんあります。私の意見では、最もクールなのはジェネリックによる型推論です。次の例をご覧ください(Josh BlochのEffective Java 2nd Edition)から引用):

...
Map<String, Integer> myMap = createHashMap();
...
public <K, V> Map<K, V> createHashMap() {
    return new HashMap<K, V>();
}

これはあまり効果的ではありませんが、ジェネリック型が長い(またはネストされている、つまりMap<String, List<String>>)。

3
jigawot

SunからJavaドキュメンテーション、「ジェネリックを使用する理由は?」

「Genericsは、コレクションのタイプをコンパイラに伝える方法を提供します。これにより、チェックできるようになります。コンパイラがコレクションの要素タイプを知ると、コンパイラは、コレクションを一貫して使用し、挿入できることをチェックできますコレクションから取り出される値の正しいキャスト...ジェネリックを使用するコードはより明確で安全です。..コンパイラは、コンパイル時に型制約に違反していないことを確認できます。 runtime[emphasis mine]。プログラムは警告なしでコンパイルされるため、実行時にClassCastExceptionがスローされないことを確実に述べることができます。 、は読みやすさと堅牢性の向上です。[強調マイン] "

2
Demi

jvmはとにかくキャストします...ジェネリック型を「オブジェクト」として扱い、目的のインスタンス化へのキャストを作成するコードを暗黙的に作成します。 Javaジェネリックは単なる構文糖です。

2

ミッチェルが指摘するように、主な利点は、複数のクラスを定義する必要のない強力な型付けです。

このようにして、次のようなことができます。

List<SomeCustomClass> blah = new List<SomeCustomClass>();
blah[0].SomeCustomFunction();

ジェネリックがなければ、blah [0]を正しい型にキャストしてその機能にアクセスする必要があります。

2
Kevin Pang

私はこれがC#の質問であることを知っていますが、 generics は他の言語でも使用されており、その使用/目標は非常に似ています。

Javaコレクションでは、 generics Java 1.5。

ほとんどすべての場所で見られる例は、2つのオブジェクトを保持するPairクラスですが、これらのオブジェクトを一般的な方法で処理する必要があります。

class Pair<F, S> {
    public final F first;
    public final S second;

    public Pair(F f, S s)
    { 
        first = f;
        second = s;   
    }
}  

このPairクラスを使用するときはいつでも、処理するオブジェクトの種類を指定でき、実行時ではなくコンパイル時に型キャストの問題が発生します。

ジェネリックは、キーワード「super」および「extends」で境界を定義することもできます。たとえば、ジェネリック型を処理したいが、Foo(setTitleメソッドがある)というクラスを拡張することを確認したい場合:

public class FooManager <F extends Foo>{
    public void setTitle(F foo, String title) {
        foo.setTitle(title);
    }
}

あまり興味深いものではありませんが、FooManagerを扱うときはいつでもMyClassタイプを処理し、MyClassがFooを拡張することを知っていると便利です。

2
etchasketch

たとえば、SpringORMおよびHibernateで実装されたGenericDaoでこれらを使用します。

public abstract class GenericDaoHibernateImpl<T> 
    extends HibernateDaoSupport {

    private Class<T> type;

    public GenericDaoHibernateImpl(Class<T> clazz) {
        type = clazz;
    }

    public void update(T object) {
        getHibernateTemplate().update(object);
    }

    @SuppressWarnings("unchecked")
    public Integer count() {
    return ((Integer) getHibernateTemplate().execute(
        new HibernateCallback() {
            public Object doInHibernate(Session session) {
                    // Code in Hibernate for getting the count
                }
        }));
    }
  .
  .
  .
}

ジェネリックを使用することにより、このDAOの実装は、GenericDaoをサブクラス化することにより、開発者に設計されたエンティティのみを渡すように強制します。

public class UserDaoHibernateImpl extends GenericDaoHibernateImpl<User> {
    public UserDaoHibernateImpl() {
        super(User.class);     // This is for giving Hibernate a .class
                               // work with, as generics disappear at runtime
    }

    // Entity specific methods here
}

私の小さなフレームワークはより堅牢です(フィルタリング、遅延読み込み、検索などがあります)。ここで例を挙げて簡単に説明します

私は、スティーブやあなたと同じように、最初に言った"面倒で複雑すぎる"だが、今ではその利点がわかる

1
victor hugo

ジェネリックを使用すると、厳密に型指定されたオブジェクトを作成できますが、特定の型を定義する必要はありません。最も有用な例は、リストと同様のクラスだと思います。

ジェネリックリストを使用すると、リストリストリストを自由に作成でき、常に強い型付けを参照できます。変換する必要はなく、配列または標準リストのように変換する必要はありません。

1
Mitchel Sellers

ジェネリックを使用すると、任意のオブジェクトを保持できるオブジェクトおよびデータ構造に厳密な型指定を使用できます。また、ジェネリック構造からオブジェクトを取得するとき(ボックス化/アンボックス化)の面倒で高価なタイプキャストを排除します。

両方を使用する1つの例は、リンクリストです。オブジェクトFooのみを使用できる場合、リンクリストクラスはどのようになりますか?任意の種類のオブジェクトを処理できるリンクリストを実装するには、リストに1種類のオブジェクトのみを含める場合、リンクリストと仮想ノード内部クラスのノードが汎用である必要があります。

1
Steve Landey

「型の安全性」や「キャスティングなし」などの明らかな利点はすでに言及されているので、他の「利点」についてお話ししたいと思います。

まず、ジェネリックは言語に依存しない概念であり、IMO、通常の(実行時)ポリモーフィズムを同時に考えるとより理にかなっているかもしれません。

たとえば、オブジェクト指向設計からわかっているポリモーフィズムには、プログラムの実行時に呼び出し元オブジェクトが実行時に把握され、関連するメソッドがランタイムタイプに応じて呼び出されるというランタイム概念があります。ジェネリックでは、考え方は多少似ていますが、すべてがコンパイル時に発生します。それは何を意味し、どのようにそれを利用しますか?

(コンパクトに保つ​​ために汎用メソッドに固執しましょう)これは、(多態性クラスで以前に行ったように)別々のクラスで同じメソッドを使用できることを意味しますが、今回はコンパイラーによって自動生成されます。コンパイル時に。コンパイル時に指定した型でメソッドをパラメーター化します。そのため、メソッドを最初から作成する代わりにすべての単一型ランタイムポリモーフィズム(メソッドのオーバーライド)で行うように、コンパイル中にコンパイラーに作業を行わせます。これは、システムで使用される可能性のあるすべての型を推測する必要がないため、コードを変更せずにはるかにスケーラブルになるため、明らかな利点があります。

クラスはほぼ同じように機能します。型をパラメータ化すると、コンパイラによってコードが生成されます。

「コンパイル時間」の概念が得られたら、「境界付き」型を使用して、クラス/メソッドを介してパラメーター化された型として渡すことができるものを制限できます。そのため、特に他の人がフレームワークを使用している場合、何を通過させるかを制御できます。

public interface Foo<T extends MyObject> extends Hoo<T>{
    ...
}

現在、MyObject以外のsthを設定することはできません。

また、メソッド引数に型制約を「強制」することができます。つまり、両方のメソッド引数が同じ型に依存することを確認できます。

public <T extends MyObject> foo(T t1, T t2){
    ...
}   

これがすべて理にかなっていることを願っています。

1
stdout

Generics(特にコレクション/リスト)を使用するもう1つの利点は、コンパイル時の型チェックを取得できることです。これは、オブジェクトのリストの代わりに汎用リストを使用する場合に非常に便利です。

1

コレクションに値タイプが含まれている場合、コレクションに挿入するときにオブジェクトをボックス化/ボックス化解除する必要がないため、パフォーマンスが劇的に向上します。 resharperのようなクールなアドオンは、foreachループなど、より多くのコードを生成できます。

1
gt124

最も単一の理由は、それらが提供することですタイプセーフティ

List<Customer> custCollection = new List<Customer>;

とは対照的に、

object[] custCollection = new object[] { cust1, cust2 };

簡単な例として。

1
Vin

要約すると、ジェネリックを使用すると、目的をより正確に指定できます(より強力な入力)。

これには、いくつかの利点があります。

  • コンパイラーはユーザーが何をしたいのかをよりよく知っているので、型に互換性があることを既に知っているため、多くの型キャストを省略することができます。

  • これにより、プログラムの修正に関する以前のフィードバックも得られます。以前は実行時に失敗するはずだったもの(たとえば、オブジェクトを目的の型にキャストできなかったため)が、コンパイル時に失敗し、テスト部門が暗号化されたバグレポートを作成する前に間違いを修正できます。

  • コンパイラは、ボクシングの回避など、より多くの最適化を実行できます。

1
Thomas Danecker

追加/拡張するいくつかの事項(.NETの観点から言えば):

ジェネリック型を使用すると、ロールベースのクラスとインターフェイスを作成できます。これはすでにより基本的な用語で述べられていますが、型にとらわれない方法で実装されたクラスを使用してコードを設計し始めたことがわかります。

メソッドの一般的な引数でも同じことができますが、キャストに「Tell Do n't Ask」の原則を適用するのにも役立ちます。

1
SpongeJim

コレクションにジェネリックを使用するのは簡単でクリーンです。あなたが他のどこでもそれをパントしても、コレクションからの利益は私にとって勝利です。

List<Stuff> stuffList = getStuff();
for(Stuff stuff : stuffList) {
    stuff.do();
}

List stuffList = getStuff();
Iterator i = stuffList.iterator();
while(i.hasNext()) {
    Stuff stuff = (Stuff)i.next();
    stuff.do();
}

または

List stuffList = getStuff();
for(int i = 0; i < stuffList.size(); i++) {
    Stuff stuff = (Stuff)stuffList.get(i);
    stuff.do();
}

それだけでジェネリックの限界的な「コスト」の価値があり、これを使用して価値を得るためにジェネリックの第一人者である必要はありません。

0
Will Hartung

ジェネリックを使用すると、型固有のサポートを提供しながら、より再利用可能なオブジェクト/メソッドを作成することもできます。また、場合によっては多くのパフォーマンスを得ることができます。 Java Genericsの完全な仕様はわかりませんが、.NETでは、Implements a Interface、Constructor、Derivationなど、Typeパラメーターに制約を指定できます。

0
Eric Schneider

私はかつてこのトピックについて講演しました。 http://www.adventuresinsoftware.com/generics/ で私のスライド、コード、およびオーディオ録音を見つけることができます。

0
Michael L Perry