黒馬プログラマー----ハイテク----のJAVA汎用型と類搭載器

8036 ワード

-----------------------androidトレーニング、javaトレーニング、お客様との交流を楽しみにしています!----------------


1、入門汎用型の基本応用


汎用型はjavacコンパイラに提供され、セット内の入力タイプを限定し、コンパイラがソースプログラムの不正な入力をブロックするようにすることができます.コンパイラがタイプ説明付きのセットをコンパイルすると、「タイプ」情報が除去され、プログラムの実行効率に影響を与えません.パラメータ化された汎用型では、getClass()メソッドの戻り値は元のタイプと全く同じです.コンパイルにより生成されたバイトコードは汎用型のタイプ情報を除去するので,コンパイラをスキップできれば,ある汎用型の集合に他のタイプのデータを加えることができ,例えば反射で集合を得てaddメソッドを呼び出すことができる.

2、汎用型の内部原理及び更なる応用


・強制タイプ変換は面倒ですが、各Objectの具体的なタイプが何なのかを事前に知っておくと、正しい変換ができます.そうでなければ、変換のタイプが間違っている場合は、例えば「Hello Generics!」文字列を強制的にDoubleに変換すると、コンパイル時にエラーは報告されませんが、実行時に切ります.それは強制的に変換しない方法がありますか--はい、Java 5の汎用型で実現します.
・ArrayListクラス定義およびArrayListクラス参照には、以下の用語が含まれる.
全体をArrayList汎用タイプと呼ぶ
ArrayListのEをタイプ変数またはタイプパラメータと呼ぶ
ArrayList全体をパラメトリックタイプと呼ぶ
ArrayListのIntegerをタイプパラメータと呼ぶインスタンスまたは実際のタイプパラメータ
ArrayListの<>はtypeofを読んでいます
ArrayListを元のタイプと呼ぶ
・パラメトリックタイプと元のタイプの互換性:
パラメトリックタイプは、レポート警告をコンパイルする元のタイプのオブジェクトを参照できます.たとえば、Collection c=new Vector();//いいですか.コンパイラの一言のことではありませんか.
元のタイプはパラメトリックタイプのオブジェクトを参照し、レポート警告をコンパイルできます.たとえば、Collection c=new Vector();//もとの方法は1つの集合パラメータを受け入れて、新しいタイプも伝わることができます
・パラメトリックタイプタイプタイプパラメータの継承関係を考慮しない:
Vector v = new Vector();//間違い!////書かないのは間違いない,書いたのは故犯を知っているからだ.
Vector v = new Vector();//間違い!
・コンパイラは、汎用変数の配列を作成できません.すなわち、配列インスタンスを作成するときに、配列の要素はパラメータ化されたタイプを使用できません.たとえば、次の文にエラーがあります.
  Vector vectorList[] = new Vector[10];
・思考問題:次のコードはエラーを報告しますか?
Vector v1 = new Vector(); 
Vector v = v1;

3、汎用型のワイルドカード拡張応用


・質問:
任意のパラメトリックタイプのセット内のすべてのデータを印刷する方法を定義します.この方法はどのように定義しますか?
・エラー方式:
public static void printCollection(Collection cols) {
for(Object obj:cols) {
System.out.println(obj);
}
/* cols.add("string");//間違いない
 cols = new HashSet();//エラーが報告されます!*/
}
・正しい方法:
public static void printCollection(Collection> cols) {
for(Object obj:cols) {
System.out.println(obj);
}
//cols.add("string");//間違い、それは自分の未来が一致するのがきっとStringであることを知らないためです
cols.size();//はい、このメソッドはタイプパラメータとは関係ありません.
 cols = new HashSet();
}
・まとめ:
使用しますか?ワイルドカードは他のパラメータ化されたタイプを参照できますか?ワイルドカードで定義された変数は主に参照として使用され、パラメータ化に関係のないメソッドを呼び出すことができ、パラメータ化に関連するメソッドを呼び出すことはできません.
・ワイルドカードの上境界を限定する:
正しい:Vector extends Number>x=new Vector()
エラー:Vector extends Number>x=new Vector()
・ワイルドカードの下境界を限定する:
正しい:Vector super Integer>x=new Vector()
エラー:Vector super Integer>x=new Vector()
・ヒント:
ワイルドカードには常に自分が含まれていることを制限します.
?参照としてのみ使用でき、他の変数に値を割り当てることはできません.
Vector extends Number> y = new Vector();
Vector x = y;
上のコードエラー、原理とVectorx 11=new Vector()似ています
強制タイプ変換でのみ値を割り当てることができます.

4、汎用集合の総合応用例


 
HashMap hm = new HashMap();

  hm.put("zxx",19);

  hm.put("lis",18);

  

  Set> mes= hm.entrySet();

  for(Map.Entry me : mes) {

   System.out.println(me.getKey() + ":" + me.getValue());

  }

jspページでもSetまたはMapのセットを反復することがよくあります.


${entry.key}:${entry.value}


5、カスタム汎用方法及びその応用


次の関数の構造は似ています.タイプのみが異なります.
int add(int x,int y) {

return x+y;

 }

float add(float x,float y) {

return x+y;

}

double add(double x,double y) {

return x+y;

}

C++はテンプレート関数で解決して、ただ1つの共通の方法だけを書いて、それは各種のタイプに適応することができて、模式コードは以下の通りです:
template 

T add(T x,T y) {

return (T) (x+y);

}

Javaの汎用メソッドはC++テンプレート関数の機能が強くなく、javaの次のコードはコンパイルできません.
 T add(T x,T y) {

return (T) (x+y);

//return null;

}

汎用型のタイプパラメータを配置するために使用されるカッコは、メソッドの他のすべての修飾子の後、およびメソッドの戻りタイプの前、すなわち戻り値の直前に表示されます.通常、タイプパラメータは通常、単一の大文字で表されます.
配列内の2つの要素の位置を交換する汎用メソッド構文は、次のように定義されます.
static  void swap(E[] a, int i, int j) {

E t = a[i];

a[i] = a[j];

a[j] = t;

}

汎用メソッドの実際のパラメータとして使用できるのは、参照タイプのみであり、swap(new int[3],3,5);文はコンパイルエラーを報告します.
汎用を適用する場合にはextends限定子を用いることができるほか、汎用を定義する場合にはextends限定子、例えばClassを用いることもできる.getAnnotation()メソッドの定義.void method(){}のような複数の境界を&で指定できます.
一般的な方法、構造方法、静的方法では、汎用を使用できます.
パラメータ化された例外と呼ばれるタイプ変数で例外を表すこともできます.メソッドのthrowsリストで使用できますが、catch句では使用できません.
汎用型では、複数のタイプのパラメータを同時に使用できます.たとえば、定義されたカッコにカンマを使用します.
public static  V getValue(K key) { return map.get(key);}

6、カスタム汎用クラスの応用


クラスのインスタンス・オブジェクトの複数の場所で同じ汎用パラメータが使用される場合、これらの場所で参照される汎用タイプが同じ実際のタイプを維持する場合は、汎用タイプ、すなわちクラス・レベルの汎用を定義します.構文フォーマットは次のとおりです.
public class GenericDao {

private T field1;

public void save(T obj){}

public T getById(int id){}

}

クラスレベルの汎用型は、クラス名を参照するときに指定したタイプ情報に基づいてタイプ変数をパラメータ化します.たとえば、次の2つの方法があります.
GenericDao dao = null;

new genericDao();

注意:
汎用タイプをパラメータ化する場合は、タイプパラメータのインスタンスは参照タイプでなければなりません.基本タイプではありません.
1つの変数が汎用として宣言されると、インスタンス変数、メソッド、および内部クラスのみで呼び出され、静的変数および静的メソッドでは呼び出されません.静的メンバーはすべてのパラメータ化されたクラスによって共有されるため、静的メンバーにはクラスレベルのタイプパラメータがあるべきではありません.
質問:クラスで汎用を使用する方法は1つしかありません.クラスレベルの汎用を使用しますか、それともメソッドレベルの汎用を使用しますか.

7、反射によって汎用型の実際型パラメータを得る


サンプルコード:
Class GenericalReflection {

  private Vector dates = new Vector();

  public void setDates(Vector dates) {

    this.dates = dates;

  }

  public static void main(String[] args) {

   Method methodApply = GenericalReflection.class.getDeclaredMethod("applyGeneric", Vector.class);

   ParameterizedType pType = (ParameterizedType)

                    (methodApply .getGenericParameterTypes())[0];

            System.out.println("setDates("

                    + ((Class) pType.getRawType()).getName() + ")" );

  }

}

汎用DAOの応用:
public abstract class DaoBaseImpl implements DaoBase {

protected Class clazz;

public DaoBaseImpl() {

Type type = this.getClass().getGenericSuperclass();

ParameterizedType pt = (ParameterizedType) type;

this.clazz = (Class) pt.getActualTypeArguments()[0];

System.out.println("clazz = " + this.clazz);

}

}

public class ArticleDaoImpl extends DaoBaseImpl
implements ArticleDao { }

8.クラスローダ及びその委託メカニズム


クラス・ローダとクラス・ローダの役割について簡単に説明します.
Java仮想マシンには複数のクラスローダをインストールできます.システムのデフォルトでは3つの主要クラスローダがあります.各クラスは特定の場所のクラスをロードします.BootStrap、ExtClassLoader、AppClassLoaderです.
クラス・ローダもJavaクラスです.他のjavaクラスのクラス・ローダ自体もクラス・ローダにロードされるため、Javaクラスではない最初のクラス・ローダが必要であることは明らかです.これはBootStrapです.
Java仮想マシン内のすべてのクラス・マウンタは、親子関係のあるツリー構造で構成されています.各クラス・マウンタ・オブジェクトをインスタンス化する場合は、親クラス・マウンタ・オブジェクトを指定するか、デフォルトでシステム・クラス・マウンタを使用して親クラス・ロードを指定する必要があります. 
Java仮想マシンがクラスをロードする場合、いったいどのクラスローダをロードに派遣しますか?
まず、現在のスレッドのクラスローダは、スレッドの最初のクラスをロードします.
クラスAにクラスBが参照されている場合、Java仮想マシンはクラスAをロードするクラスローダを使用してクラスBをロードします. 
ClassLoaderを直接呼び出すこともできます.loadClass()メソッドは、クラスローダがクラスをロードすることを指定します.
各クラス・ローダがクラスをロードする場合は、上位クラス・ローダに委任します.
すべての祖先クラスのローダがクラスにロードされていない場合、発起者クラスのローダに戻ってもロードできない場合は、ClassNotFoundExceptionを投げて、発起者クラスのローダの息子を探すのではなく、getChildメソッドがないため、あっても、複数の息子がいて、どれを探していますか?
クラスローダの階層図と委託ロード原理に対して、以前ClassLoaderTestをjre/lib/extディレクトリの下のitcastに出力したことを説明する.JArパッケージ内で実行結果がExtClassLoaderの原因となります.
カスタムクラスローダはClassLoaderを継承する必要があります
loadClassメソッドとfindClassメソッド
defineClassメソッド
テンプレートメソッド設計モード:
親-->loadclass/findClass();/取得classファイルの変換-バイトコード-->defineClass()
子1(自分でやる)
子2(自分でやる)