まず、ジェネリック医薬品のコンセプト
私たちはしばしばのためのデータのより多くの種類実行する必要があり、同様の動作をするが、各タイプのために調製し、クラスメソッドは、非常に非効率的です。このためには、JDK 5-導入ジェネリックを。
ジェネリック医薬品が提供コンパイル時検出メカニズムで型の安全性を、このメカニズムは、プログラマができるようにする違法なタイプのコンパイル時間を検出します。
ジェネリックのエッセンスタイプのパラメータ、パラメータとして渡されるデータのタイプ。
Typeパラメータでなければなりません参照型タイプ。
第二に、一般的な
1.一般的な方法
一般的な方法は、受信されるときに呼び出すの異なる種類のパラメータを、所定の戻り値の異なるタイプ。
次のように一般的な方法が定義されています。
<类型参数声明>返回类型 方法名(形参表){
//方法定义
}
以下は簡単な例であり、一般的な方法は、2つの方法を使用して呼び出されます。
public class Demo {
public static void main(String[] args) {
Integer i = 123;
Demo.<Integer>print(i); //给定类型参数调用,该方法必须配合使用句点表示法,无法自动推断时使用
print(i); //Java8新增类型推断,一般采用该方法
}
public static <T> void print(T t) {
System.out.println(t);
}
}
あなたが特定の範囲(通常は内のパラメータを入力したい場合は、継承階層の範囲)は、使用することができます拡張キーワードを。このキーワードは、type引数がなければなりません指定したクラスを継承または実装インタフェースを。
//如没有extends,编译无法通过,因为不知道T是否定义了compareTo方法
public <T extends Comparable<T>> boolean smallerThan(T o1,T o2) {
if(o1.compareTo(o2) < 0)
return true;
else
return false;
}
一般的な方法を使用することもできる可変パラメータなどを、。
public <T> void print(T...args) {
for(T t : args)
System.out.println(t);
}
2.ジェネリッククラス
ジェネリッククラスは、異なる種類のデータを開くことができる同じインターフェイス。最も典型的には、各種のあるコンテナクラス。
次のように一般的なクラスが定義されています。
class 类名<类型参数声明>{
//实例/局部变量和实例方法可以使用类声明的类型参数
}
以下は簡単な例であり、2つの方法で使用します:
class Test<T>{
T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
public class Demo {
public static void main(String[] args) {
//方法一:给定类型实参,实例对象只能接受给定类型的数据
Test<Integer> test1 = new Test<Integer>();
test1.set(6);
//方法二:不给定类型实参,实例对象可以接受任何类型的数据
Test test2 = new Test();
test2.set(1);
test2.set(2.0);
test2.set("3");
}
}
ジェネリックメソッド呼び出しごとが再びますプッシュしているので、再型推論に安全。これは、自動推論の場合に使用する必要があります。
ジェネリッククラスのインスタンス初期化したら、その範囲は、内持続します。中に変更されたTypeパラメータ危険なは、引数で与えられるべきです。
● 一般的な一般的な方法があります
:メソッドのジェネリッククラスのような一般的な方法、ありません
class Test<T>{
T value;
public void set(T value) { //不是一个泛型方法,只是使用了类声明的类型形参
this.value = value;
}
public T get() { //同上,不是一个泛型方法
return value;
}
public <E> void print(E arg){ //这是一个泛型方法,他有单独的类型参数声明,这个方法中T和E均可使用
System.out.print(arg.toString());
}
public <T> void println(T arg) { //这也是一个泛型方法,但它将类给定的类型参数T隐藏(屏蔽)了,这里的T是自身的类型形参
System.out.println(arg.toString());
}
//这两个方法主要是为了说明泛型类中的泛型方法,明确概念,两个函数本身不具应用意义
}
● 静的メソッドとジェネリック
静的メソッドがアクセスできないインスタンス部材、及び一種類のパラメータの一例は、その結果、部材であり、静的メソッドは、型パラメータのクラスを使用することはできません。
上記の例では、メソッドをコンパイルしていない次の静的クラスを追加します。
public static void print2(T arg){ //Error:不能对非静态类型T进行静态引用
System.out.println(arg);
}
それは次のようにネイティブ型パラメータが変更され、静的メソッドとして宣言されています:
public static <T> void print2(T arg) {
System.out.println(arg);
}
3.ジェネリックインターフェイス
汎用インタフェース定義と実質的に同じ一般的なクラスは、しばしばなどの様々な種類の製造に使用されるコンパレータ。
interface Print <T>{ //输出器
public void print(T o);
}
ジェネリッククラスが実装インタフェースを使用する場合、インターフェイスは、ジェネリック型パラメータを渡す必要があります。ジェネリッククラスの汎用インタフェースに共通の伝送パラメータ:
interface Print <T>{
public void print(T o);
}
class Test<T> implements Print<T>{
@Override
public void print(T o) {
System.out.println(o);
}
}
4.ワイルドカード
ジェネリッククラスはパラメータの異なる種類でインスタンス化されると、それは異なることになるバージョン。異なるバージョンの例は、互換性がないことは、基本クラスおよびサブクラスの間であっても、。
public class Demo {
public static void main(String[] args) {
test(new Test<Base>()); //无错误
test(new Test<Heir>()); //Error:方法 test(Test<Base>)对于参数(Test<Heir>)不适用
}
public static void test(Test<Base> arg) { //规定仅接受Test<Base>版本,<>里必须给定类型,否则报错
System.out.println(arg);
}
}
class Base{}
class Heir extends Base{}
class Test<T>{}
この問題を解決するために、我々が使用する?とワイルドカードの種類、それはすべてのタイプを参照することができます。上記試験方法は次のように、改変コンパイルすることができます。
//public static void test(Test<Base> arg)
public static void test(Test<?> arg) {
System.out.println(arg);
}
ジェネリックの上限と下限
ジェネリックを使用している場合、我々は受け入れることができますタイプのパラメータが定義され、上下の境界を。
入ってくるタイプの規定は、インターフェース(実装/サブクラスの型でなければならない上限を)、または親クラス(いくつかの種類が存在しなければならない下限)。
所定の上限には、キーワードに延び、上限は、実施例の部材ジェネリック親クラス内の所定のを可能にする、および可能よい多型。
public class Demo {
public static void main(String[] args) {
test(new Test<Base>(new Base())); //class learning_test.Base
test(new Test<Heir>(new Heir())); //class learning_test.Heir
}
public static void test(Test<? extends Base> arg) {
arg.print();
}
}
class Base{}
class Heir extends Base{}
class Test<T>{
T value;
public Test (T value) {
this.value = value;
}
public void print() {
System.out.println(value.getClass().toString());
}
}
スーパーキーワードが下限を指定するために使用される、すなわち、唯一の特定のタイプの受信親クラスタイプを。パラメータビットテスト<?スーパー相続人>上記の試験は、主プロセスは説明します。
test(new Test<Base>(new Base())); //无措
test(new Test<Heir>(new Heir())); //Error:方法 test(Test<? super Base>)对于参数(Test<Heir>)不适用
テストが見つかった場合は、任意の汎用のために拡張を使用することができるが、唯一の超ワイルドカードの種類で使用することができます。
public static <T extends Base> void print1(T o){} //无错误
public static <T super Base> void print2(T o){} //Error:标记“super”上有语法错误,应为,
//第二行的错误报告看上去很奇怪,可能是将super识别为父类关键字super使用了
public static void print3(List<? extends Base> list) {} //无错误
public static void print4(List<? super Base> list) {} //无错误