一般的な制約と制限
消去によってジェネリック型、およびブリッジ型変換方法力を達成するため、(ほとんど消失から)一定の制限があります。
基本的なタイプの例は、パラメータの種類を使用することはできません
タイプパラメータが基づいている、実質的にすることができるラッパー型パッケージを使用する(これはポスト消去型パラメータとして型にObject
クラス型ベース値格納することができません)。パッケージは、置換クラスタイプ・パラメータを受け入れることができない場合の処理のためのクラスおよびメソッドを分離するために使用されてもよいです。
ファイル名を指定して実行時の型のクエリは元の型に適用されます
仮想マシンのオブジェクトは、特定のプリミティブ型なので、クエリの種類のみクエリプリミティブ型を持っていたよう。
// 只能测试a是否为某种Pair类型
if (a instanceof Pair<String>) {...}
if (a instanceof Pair<T>) {...}
Pair<String> p = (Pair<String>) a;
使用するコードの試みは、ときにinstanceof
オブジェクトがジェネリック型に属しているかどうかを照会するときに、コンパイラが文句を言うでしょう。あなたはキャストを使用する場合は警告が表示されます。
同様に、場合でも、getClass
この方法は、オリジナルタイプに戻ることができます。
あなたは、パラメータ化された型の配列を作成することはできません
消去タイプので、元の型のみ、もしそうであれば、パラメータは、配列型の作成が、それはアップキャスト配列の後であってもよいことができObject[]
、その後の追加に提供されるパラメータの種類以外のパラメータジェネリック型定義オブジェクト。安全要件の違反のこのタイプ。
Pair<String> table = new Pair<String>[10];
Object[] = objArray = table;
// objArray记住了table的原始类型Pair,因此存储String类会抛出ArrayStoreException异常
objArray[0] = "Hello";
// objArray只记住了Pair,因此添加Pair<Employee>也不会编译报错,但会导致类型错误
objArray[0] = new Pair<Employee>();
注:配列は、配列変数を宣言することは許されないが、使用することができないという意味ではありません作成することを許可していないnew
、それを初期化します。
注2:あなたは、ワイルドカード型の配列、そして初期化変数の型変換を宣言することができますが、これはまだ安全ではありません。
ヒント:安全かつ効果的に収集パラメータ化型オブジェクトへの唯一の方法ですArrayList:ArrayList<Pair<String>>
。
可変引数警告
パラメータ方式の可変数にジェネリック型のインスタンスを渡されると、実際には、仮想マシンは、配列のパラメータ化された型を作成することはできません規程に違反パラメータ法、などのアレイのパラメータ化された型を確立する必要があります。しかし、コンパイラは警告ではなくエラーを発行します。
正しく呼び出すために、あなたは注釈または使用することができたときに決定することができる@SafeVarargs
警告をキャンセルする標識法を。
Type変数インスタンス化することはできません
あなたは、インスタンス化することはできませんT
、それが消去されるように、種類Object
のタイプを。
最良の解決策は、発信者が受信する方法で設計することであるコンストラクタ式、提供できるようにすることでSupplier<T>
取得する機能インタフェースをT
インスタンスのタイプ。この時点でT
消去されるのを恐れることなく、着信インターフェイスの決定の関数です。
// 向该方法传入构造器引用即可获取T类型的实例
public static <T> Pair<T> makePair(Supplier<T> constr) {
return new Pair<>(constr.get(), constr.get());
}
私たちは、一般的な配列を構築することができません
タイプの制限が存在する場合には、消去の形成における配列の結果のタイプは常にタイプを制限します。
一般的な配列は唯一のプライベートドメインクラスのインスタンスとして、これは配列として宣言することができる場合はObject[]
、変換の種類をするときの要素を取得することができます。
一般的なグループは、その使用の番号を持っている場合、参照が正しいタイプのアレイを生成するコンストラクタを提供しなければなりません。この方法の例としては、一般的な変数に似ています。
ジェネリッククラス型変数の静的コンテキストが無効です。
静的メソッドは、静的な設計の一般的なドメインを返した場合は、消去方法の種類は、リターンにつながるObject
静的フィールドのタイプ。静的フィールドは、一般的なクラスのすべてのオブジェクトで共有されるように、オブジェクトに適用されないことがあります。
// 擦除类型后静态变量为Object类型
public class Singleton<T> {
private static T singleInstance;
private static T getSingleInstance() {
if (singleInstance == null) // construct new instance of T
return singleInstance;
}
}
// 无法确定返回类型
SingletonA = new Singleton<Integer>();
SingletonB = new Singleton<Boolean>();
Singleton.getSingleInstance();
ジェネリッククラスのインスタンスを投げるか、キャプチャしません
ジェネリッククラスは、拡張禁止Thorwable
インタフェースを。しかし、一般的なタイプは、T
拡張することができるThrowable
インタフェースを、しかし、キャッチまたはスローすることはできません。
// 不合法
public static <T extends Throwable> void doWork(Class<T> t) {
try {
// doWork
}catch (T e) {
Logger.global.info(...);
}
}
// 合法
public static <T extends Throwable> void doWork(T t) throws T {
try {
// doWork
}catch (Throwable realCause) {
t.initCause(realCause);
// t被擦除为Throwable类,然后返回后被调用者强制转换为T类型
throw t;
}
}
あなたは、チェック例外の検査を排除することができます
ジェネリック医薬品の使用は、同時にすべてのチェック例外プロセッサを提供することができます。
スレッドのプログラムを考えてみます。
package tClass;
public abstract class Block {
public abstract void body() throws Exception;
public Thread toThread(){
return new Thread() {
// run方法声明不抛出异常
public void run() {
// 将所有异常转换为编译器认为的非受查异常
try{
body();
}catch (Throwable t) {
Block.<RuntimeException>throwAs(t);
}
}
};
}
@SuppressWarnings("unchecked")
public static <T extends Throwable> void throwAs(Throwable e) throws T {
throw (T)e;
}
}
package tClass;
import java.io.File;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
new Block() {
// body方法打开不存在的文件,抛出受查异常FileNotFoundException
public void body() throws Exception {
Scanner in = new Scanner(new File("notExistedFile"), "UTF-8");
while(in.hasNext())
System.out.println(in.next());
}
}.toThread().start();
}
}
上記の方法により、捕捉しないrun
だけでコンパイラを作るために、法によってチェックされない例外を非チェック例外をスローすると思います。run
異常の種々の生成方法は、非異常複数のキャプチャするためにこの技術を書き込む回避し、例外をスロー調査面倒コード下で包装ケース。
紛争後に消去することを注意
ジェネリッククラスはスーパークラスのメソッドをオーバーライドする場合は、パラメータの型が過負荷になっている場合、T
それは消去されますObject
。これは、紛争につながる可能性があります。
public class Pair<T> {
// 被擦除为eqauls(Object value)与从Object类继承的equals(Object)冲突
public boolean equals(T value) {return first.equals(value) && second.eqauls(value);}
}
一般的な仕様の原則は:変換のサポート消去のために、我々は、インタフェースサブクラスの2種類のすることはできませんクラスやタイプの変数に制限を課す必要がある同じインターフェイスの異なるパラメータの二つのインターフェース中。
同じインタフェースの二つの異なるパラメータの実装は、あなたが紛争にまったく同じ2つのシグネチャブリッジアプローチのリードを取得する場合は、インターフェイスを受け取るクラスのブリッジメソッドのインタフェースパラメータを達成するために:その理由は、これらの原則の存在があることです。