私はこのソフトボールを公園から打ちたい人に提供したいと思いました。ジェネリックとは何ですか、ジェネリックの利点は何ですか、なぜ、どこで、どのように使用する必要がありますか?かなり基本的なものにしてください。ありがとう。
私はこのソフトボールを公園から打ちたい人に提供したいと思いました。ジェネリックとは何ですか、ジェネリックの利点は何ですか、なぜ、どこで、どのように使用する必要がありますか?かなり基本的なものにしてください。ありがとう。
回答:
私は自分自身を繰り返すのが本当に嫌いです。同じことを必要以上に頻繁に入力するのは嫌いです。少しの違いはあるものの、何度も言い直すのは好きではありません。
作成する代わりに:
class MyObjectList {
MyObject get(int index) {...}
}
class MyOtherObjectList {
MyOtherObject get(int index) {...}
}
class AnotherObjectList {
AnotherObject get(int index) {...}
}
再利用可能なクラスを1つ作成できます...(何らかの理由でrawコレクションを使用したくない場合)
class MyList<T> {
T get(int index) { ... }
}
私は今では3倍効率が良く、1つのコピーを維持するだけで済みます。なぜあなたはより少ないコードを維持したくないのですか?
これは、他のクラスと相互作用するCallable<T>
必要がReference<T>
あるaやaなどの非コレクションクラスにも当てはまります。本当に拡張Callable<T>
しFuture<T>
て、他のすべての関連クラスを拡張して 、タイプセーフなバージョンを作成しますか?
私はしません。
タイプキャストする必要がないことは、コンパイル時に型チェックを実行するため、Javaジェネリックの最大の利点の1つです。これにより、ClassCastException
実行時にスローされる可能性が低くなり、より堅牢なコードにつながる可能性があります。
しかし、あなたはそれを完全に知っていると思います。
Genericsを見るたびに、頭痛の種になります。Javaの最良の部分は、その単純さと最小限の構文であり、ジェネリックは単純ではなく、かなりの量の新しい構文を追加することだと思います。
最初は、ジェネリック医薬品のメリットもわかりませんでした。私は1.4構文からJavaを学び始めました(当時Java 5はリリースされていましたが)、ジェネリックスに遭遇したとき、書くコードが多いと感じ、その利点を本当に理解していませんでした。
最新のIDEを使用すると、ジェネリックスを使用したコードの記述が簡単になります。
最新のまともなIDEのほとんどは、ジェネリックスを使用したコードの記述、特にコード補完を支援するのに十分なほどスマートです。
ここで作るの例だMap<String, Integer>
とはHashMap
。入力する必要のあるコードは次のとおりです。
Map<String, Integer> m = new HashMap<String, Integer>();
そして確かに、それは新しいを作るためだけにタイプすることがたくさんありHashMap
ます。ただし、実際には、Eclipseが必要なものを認識する前に、これだけ入力する必要がありました。
Map<String, Integer> m = new Ha
Ctrl+Space
確かに、HashMap
候補のリストから選択する必要がありましたが、基本的にIDEは、汎用タイプを含め、何を追加するかを知っていました。適切なツールがあれば、ジェネリックを使用することはそれほど悪くありません。
さらに、型がわかっているため、汎用コレクションから要素を取得すると、IDEは、そのオブジェクトがすでに宣言された型のオブジェクトであるかのように動作します。IDEがオブジェクトの型を知るためにキャストする必要はありません。です。
ジェネリックスの主な利点は、Java5の新機能とうまく連携する方法にあります。整数をaに投げ込みSet
、その合計を計算する例を次に示します。
Set<Integer> set = new HashSet<Integer>();
set.add(10);
set.add(42);
int total = 0;
for (int i : set) {
total += i;
}
そのコードには、次の3つの新しいJava5機能があります。
まず、プリミティブのジェネリックスとオートボクシングにより、次の行が可能になります。
set.add(10);
set.add(42);
整数10
はInteger
、値が10
。のに自動ボックス化されます。(そして42
)についても同じです。次にInteger
、Set
それはInteger
sを保持することが知られているに投げ込まれます。をスローしようとString
すると、コンパイルエラーが発生します。
次に、for-eachループは次の3つすべてを取ります。
for (int i : set) {
total += i;
}
まず、Set
含まれているInteger
sがfor-eachループで使用されます。各要素はであると宣言さint
れており、Integer
がプリミティブにボックス化されていないため、これが許可されint
ます。そして、このアンボクシングがジェネリックがあったことを指定するために使用されたため知られて発生しているという事実Integer
で開催されたのSet
。
ジェネリックスは、Java 5で導入された新機能をまとめる接着剤になることができ、コーディングをより簡単かつ安全にするだけです。また、ほとんどの場合、IDEは適切な提案を行うのに十分なほどスマートであるため、一般的に、タイピングがそれほど多くなることはありません。
そして率直に言って、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
は、aがadd
セットに組み込まれているものです。
set.add(10);
set.add(42);
上記の行では、オートボクシングが機能しています。つまり、プリミティブint
値で10
あり、オブジェクト42
にオートボックス化されており、Integer
オブジェクトはに追加されていSet
ます。ただし、コンパイラがどの型を予期すべきかを知るのに役立つ型情報がないため、Integer
オブジェクトはObject
sとして処理されていることにSet
注意してください。
for (Object o : set) {
これは重要な部分です。for-eachループが機能する理由はSet
、Iterable
インターフェイスが実装されているためIterator
です。インターフェイスは、存在する場合はwith型の情報を返します。(Iterator<T>
、つまり。)
ただし、型情報がないため、はasの値Set
を返すanIterator
を返します。そのため、for-eachループで取得される要素は型である必要があります。Set
Object
Object
今すぐことObject
から取得されSet
、それはにキャストする必要がInteger
加算を実行するために、手動で:
total += (Integer)o;
ここでは、型キャストから行われるObject
までInteger
。この場合、これは常に機能することがわかっていますが、手動の型キャストでは、他の場所で小さな変更を加えると破損する可能性がある脆弱なコードであると常に感じます。(私はすべてのタイプキャストがClassCastException
起こるのを待っていると感じます、しかし私は逸脱します...)
これで、Integer
はボックスから解放さint
れ、int
変数への加算を実行できるようになりますtotal
。
Java 5の新機能が非ジェネリックコードで使用できることを説明できればと思いますが、ジェネリックでコードを書くほどクリーンで単純ではありません。そして、私の意見では、Java 5の新機能を最大限に活用するには、ジェネリックスを調べる必要があります。少なくとも、コンパイル時のチェックで、無効なタイプキャストが実行時に例外をスローするのを防ぐことができます。
あなたは1.5がリリースされたばかりの前のJavaのバグデータベースを検索した場合、あなたはと7倍以上のバグを見つけるだろうNullPointerException
よりをClassCastException
。したがって、バグ、または少なくとも少しのスモークテスト後も存続するバグを見つけることは素晴らしい機能ではないようです。
私にとってジェネリックの大きな利点は、重要な型情報をコードで文書化することです。その型情報をコードで文書化したくない場合は、動的に型付けされた言語、または少なくともより暗黙的な型推論を備えた言語を使用します。
オブジェクトのコレクションをそれ自体に保持することは悪いスタイルではありません(ただし、一般的なスタイルはカプセル化を効果的に無視することです)。それはむしろあなたがしていることに依存します。コレクションを「アルゴリズム」に渡すことは、ジェネリックスを使用して(コンパイル時またはその前に)チェックするのが少し簡単です。
Javaのジェネリックスは、パラメトリック多相性を促進します。型パラメーターを使用して、型に引数を渡すことができます。のようなメソッドString foo(String s)
が特定の文字列だけでなく任意の文字列s
に対してList<T>
何らかの動作をモデル化するのと同じように、そのようなタイプは特定のタイプだけでなく任意のタイプに対していくつかの動作をモデル化します。どのタイプにも、要素がsであるタイプがあるList<T>
と言います。だから、実際には型コンストラクタが。引数として型を取り、結果として別の型を構築します。T
List
T
List
これが私が毎日使っているジェネリック型の例です。まず、非常に便利な汎用インターフェース:
public interface F<A, B> {
public B f(A a);
}
このインターフェースは、いくつかの2つのタイプ、A
およびB
に対して、f
を取り、A
を返す関数(と呼ばれる)があることを示していますB
。あなたは、このインタフェースを実装し、ときA
とB
限り、あなたは機能提供として、あなたが望む任意の種類のことができf
、前者を取り、後者を返します。インターフェイスの実装例は次のとおりです。
F<Integer, String> intToString = new F<Integer, String>() {
public String f(int i) {
return String.valueOf(i);
}
}
ジェネリックス以前は、キーワードを使用してサブクラス化することでポリモーフィズムが実現されていましたextends
。ジェネリックスを使用すると、実際にはサブクラス化を廃止し、代わりにパラメトリック多相を使用できます。たとえば、任意のタイプのハッシュコードを計算するために使用されるパラメーター化された(ジェネリック)クラスについて考えてみます。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ジェネリックのこれらの制限についての記事をここに書きました。
ジェネリックスの大きな利点の1つは、サブクラス化を回避できることです。サブクラス化は、拡張が難しいクラス階層を脆弱にし、階層全体を見ずに個別に理解するのが難しいクラスになる傾向があります。
Wereasは、あなたがクラスを持っているかもしれないジェネリック医薬品の前に好きなWidget
だけ延長FooWidget
、BarWidget
およびBazWidget
、ジェネリックを使用すると、単一の一般的なクラスができWidget<A>
取りFoo
、Bar
またはBaz
そのコンストラクタであなたを与えるためにWidget<Foo>
、Widget<Bar>
とWidget<Baz>
。
ジェネリックは、ボクシングとボックス化解除のパフォーマンスへの影響を回避します。基本的に、ArrayListとList <T>を比較してください。どちらも同じコア機能を実行しますが、オブジェクトとの間でボックス化する必要がないため、List <T>の方がはるかに高速です。
Genericsの最大の利点は、コードの再利用です。多数のビジネスオブジェクトがあり、同じアクションを実行するために各エンティティに対して非常に類似したコードを作成するとします。(IE Linqから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メソッドでタイプが異なる場合、同じサービスが再利用されることに注意してください。本当にエレガント!
あなたの仕事にジェネリックを使用する理由は他にもたくさんありますが、これが私のお気に入りです。
カスタムタイプをすばやく定義する方法を提供するので、私はそれらが好きです(とにかくそれらを使用します)。
したがって、たとえば、文字列と整数で構成される構造を定義し、それらの構造の配列などにアクセスする方法についてオブジェクトとメソッドのセット全体を実装する必要がある代わりに、辞書を作成できます。
Dictionary<int, string> dictionary = new Dictionary<int, string>();
そして、コンパイラー/ IDEが残りの面倒な作業を行います。特に辞書では、最初のタイプをキーとして使用できます(繰り返し値はありません)。
型付きコレクション-使用したくない場合でも、他のライブラリや他のソースからのコレクションを処理する必要があります。
クラス作成におけるジェネリックタイピング:
public class Foo <T> {public T get()..。
キャスティングの回避-私はいつも次のようなものが嫌いでした
new Comparator {public int compareTo(Object o){if(o instanceof classIcareAbout).. ..
インターフェースがオブジェクトで表現されているためにのみ存在するはずの条件を本質的にチェックしている場合。
ジェネリックに対する私の最初の反応はあなたの反応と似ていました-「あまりにも厄介で、あまりにも複雑」。私の経験では、それらを少し使用した後は慣れてしまい、それらのないコードは明確に指定されていないように感じられ、快適さも低下します。それとは別に、Javaの世界の残りの部分はそれらを使用しているので、最終的にはプログラムを使用する必要がありますよね?
良い例を挙げましょう。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の汎用リストによって例外がスローされます。
例2。
これで2つの配列リストができました。それぞれでBar()関数を呼び出します。ArrayListはオブジェクトで埋められているため、barを呼び出す前にオブジェクトをキャストする必要があります。ただし、Fooの汎用リストにはFooのみを含めることができるため、それらに対して直接Bar()を呼び出すことができます。
foreach(object o in al)
{
Foo f = (Foo)o;
f.Bar();
}
foreach(Foo f in fl)
{
f.Bar();
}
メソッド/クラスの主要な概念がパラメーター/インスタンス変数の特定のデータ型(リンクリスト、最大/最小関数、バイナリ検索など)に厳密にバインドされていないメソッド(またはクラス)を作成したことはありませんか?など)。
カットアンドペーストの再利用や強い型付けを損なうことなく、アルゴリズム/コードを再利用できることを望んでいませんか(たとえばList
、文字列が欲しいのですが、文字列が欲しいのではList
ありません!)。
あなたがすべき理由の希望は、ジェネリック(か何かより良い)を使用します。
ジェネリックスはクラスだけでなく、メソッドでも使用できることを忘れないでください。たとえば、次のスニペットを取り上げます。
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つの使用法の簡単な例です。ジェネリックメソッドでできることは他にもたくさんあります。私の意見では、最もクールなのはジェネリックスによる型推論です。次の例を見てください(JoshBlochのEffectiveJava 2nd Editionから抜粋)。
...
Map<String, Integer> myMap = createHashMap();
...
public <K, V> Map<K, V> createHashMap() {
return new HashMap<K, V>();
}
これはあまり効果がありませんが、ジェネリック型が長い(またはネストされている、つまりMap<String, List<String>>
)場合は、混乱を減らすことができます。
Throwable
、特定の宣言された例外があるメソッド本体内からプレーンオールドをスローできないことです。別の方法は、各例外タイプを返す個別のメソッドを作成するか、を返す非ジェネリックメソッドを使用して自分でキャストを行うことThrowable
です。前者は冗長すぎてまったく役に立たず、後者はコンパイラから何の助けも得られません。ジェネリックスを使用することにより、コンパイラーは自動的に正しいキャストを挿入します。だから、問題は:それは複雑にする価値がありますか?
ミッチェルが指摘するように、主な利点は、複数のクラスを定義する必要がない強い型付けです。
このようにして、次のようなことができます。
List<SomeCustomClass> blah = new List<SomeCustomClass>();
blah[0].SomeCustomFunction();
ジェネリックスがなければ、その関数にアクセスするには、blah [0]を正しい型にキャストする必要があります。
jvmはとにかくキャストします...ジェネリック型を「オブジェクト」として扱うコードを暗黙的に作成し、目的のインスタンス化へのキャストを作成します。Javaジェネリックは単なる構文糖衣です。
これがC#の質問であることは知っていますが、ジェネリックは他の言語でも使用されており、その使用/目標は非常に似ています。
JavaコレクションはJava1.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を拡張することを知っていると便利です。
Sun Javaのドキュメントから、「なぜジェネリックを使用する必要があるのですか?」
「ジェネリックスは、コレクションのタイプをコンパイラーに伝達してチェックできるようにする方法を提供します。コンパイラーがコレクションの要素タイプを認識すると、コンパイラーは、コレクションが一貫して使用されていることをチェックし、挿入できるようになります。コレクションから取り出される値の正しいキャスト...ジェネリックスを使用するコードはより明確で安全です....コンパイラーはコンパイル時に型制約が実行時に違反されていないことを確認できます[強調鉱山]。プログラムは警告なしにコンパイルされるので、実行時にClassCastExceptionがスローされないことを確実に述べることができます。特に大規模なプログラムでジェネリックを使用することの正味の効果は、読みやすさと堅牢性の向上です。[強調鉱山]」
ジェネリックスを使用すると、任意のオブジェクトを保持できるはずのオブジェクトとデータ構造に強い型を使用できます。また、一般的な構造(ボックス化/ボックス化解除)からオブジェクトを取得するときに、面倒で費用のかかるタイプキャストを排除します。
両方を使用する1つの例は、リンクリストです。リンクリストクラスがオブジェクトFooしか使用できない場合、どのようなメリットがありますか?あらゆる種類のオブジェクトを処理できるリンクリストを実装するには、リストに1つのタイプのオブジェクトのみを含める場合は、リンクリストと仮想ノード内部クラスのノードをジェネリックにする必要があります。
ジェネリックス(特にコレクション/リスト)を使用するもう1つの利点は、コンパイル時の型チェックを利用できることです。これは、オブジェクトのリストの代わりに汎用リストを使用する場合に非常に便利です。
最も理由は、型安全性を提供することです。
List<Customer> custCollection = new List<Customer>;
とは対照的に、
object[] custCollection = new object[] { cust1, cust2 };
簡単な例として。
要約すると、ジェネリックスを使用すると、意図することをより正確に指定できます(より強力なタイピング)。
これにはいくつかの利点があります。
コンパイラはあなたが何をしたいのかをもっと知っているので、型が互換性があることをすでに知っているので、多くの型キャストを省略できます。
これにより、プログラムの正しさに関する以前のフィードバックも得られます。以前は実行時に失敗していたもの(たとえば、オブジェクトを目的のタイプにキャストできなかったため)は、コンパイル時に失敗するようになり、テスト部門が不可解なバグレポートを提出する前に間違いを修正できます。
コンパイラーは、ボクシングの回避など、より多くの最適化を行うことができます。
たとえば、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
}
私の小さなフレームワークはより堅牢です(フィルタリング、遅延読み込み、検索などがあります)。例を示すために、ここで簡略化しました
私はスティーブやあなたと同じように、最初は「面倒で複雑すぎる」と言っていましたが、今ではその利点がわかります
「型安全性」や「鋳造なし」などの明らかなメリットについてはすでに説明しているので、他の「メリット」についてお話ししたいと思います。
まず第一に、ジェネリックは言語に依存しない概念であり、IMOは、通常の(実行時の)ポリモーフィズムを同時に考えるとより理にかなっているかもしれません。
たとえば、オブジェクト指向設計からわかるように、ポリモーフィズムには実行時の概念があり、プログラムの実行が進むにつれて呼び出し元オブジェクトが実行時に把握され、実行時のタイプに応じて関連するメソッドが呼び出されます。ジェネリックスでは、考え方は多少似ていますが、すべてがコンパイル時に行われます。それはどういう意味ですか、そしてそれをどのように利用しますか?
(コンパクトに保つためにジェネリックメソッドに固執しましょう)これは、(以前にポリモーフィッククラスで行ったように)別々のクラスで同じメソッドを使用できることを意味しますが、今回はコンパイラーによって自動生成され、設定されたタイプによって異なりますコンパイル時。コンパイル時に指定した型でメソッドをパラメーター化します。したがって、実行時のポリモーフィズム(メソッドのオーバーライド)で行うように、すべての型に対してメソッドを最初から作成する代わりに、コンパイル中にコンパイラーに作業を行わせることができます。システムで使用される可能性のあるすべてのタイプを推測する必要がないため、コードを変更せずにはるかにスケーラブルになるため、これには明らかな利点があります。
クラスはほとんど同じように機能します。タイプをパラメーター化すると、コードはコンパイラーによって生成されます。
「コンパイル時」の概念を理解したら、「制限付き」型を使用して、クラス/メソッドを介してパラメーター化された型として渡すことができるものを制限できます。したがって、通過するものを制御できます。これは、特に他の人がフレームワークを消費している場合に強力です。
public interface Foo<T extends MyObject> extends Hoo<T>{
...
}
現在、MyObject以外のsthを設定することはできません。
また、メソッド引数に型制約を「適用」することができます。つまり、両方のメソッド引数が同じ型に依存することを確認できます。
public <T extends MyObject> foo(T t1, T t2){
...
}
このすべてが理にかなっていることを願っています。
コレクションにジェネリックを使用するのは簡単でクリーンです。あなたが他のどこでもそれをパントしたとしても、コレクションからの利益は私にとっての勝利です。
List<Stuff> stuffList = getStuff();
for(Stuff stuff : stuffList) {
stuff.do();
}
vs
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();
}
それだけでもジェネリックの限界「コスト」の価値があり、これを使用して価値を得るのにジェネリックの第一人者である必要はありません。
ジェネリックスは、タイプ固有のサポートを提供しながら、より再利用可能なオブジェクト/メソッドを作成する機能も提供します。また、場合によっては多くのパフォーマンスが得られます。Java Genericsの完全な仕様はわかりませんが、.NETでは、Implements a Interface、Constructor、DerivationなどのTypeパラメーターに制約を指定できます。