この記事は、Java反射メカニズムの包括的な紹介を提供することを目的としています。この記事を通して、Java Reflectionの関連コンテンツを包括的に理解できることを願っています。
この記事を読む前に、 「 Java Genericsの再オーナスト」を参照できます。
序文
Java反射メカニズムは非常に強力な機能です。春やミバティスなどの多くの大規模なプロジェクトでは、反省が見ることができます。反射メカニズムにより、操作中にオブジェクトタイプ情報を取得できます。この機能を使用して、工場モードやプロキシモードなどの設計パターンを実装でき、Javaジェネリック消去などの苦痛な問題を解決することもできます。この記事では、実用的なアプリケーションの観点からJava反射メカニズムを適用します。
反射基準
PS:この記事では、読者が反射メカニズムAPIをある程度理解する必要があります。以前にさらされていない場合は、最初に公式ドキュメントのクイックスタートを確認することをお勧めします。
反射メカニズムを適用する前に、まずオブジェクトに対応する反射Classを取得する方法を見てみましょう。 Javaには、オブジェクトの反射クラスを取得する3つの方法があります。
GetClassメソッドによって
Javaでは、各ObjectにはgetClassメソッドがあります。 GetClassメソッドを使用して、このオブジェクトの対応する反射クラスを取得できます。
string s = "ziwenxie"; class <?> c = s.getclass();
ClassクラスのstaticメソッドforNameを呼び出すこともできます。
class <?
または、 .classを直接使用することができます:
クラス<?> c = string.class;
記事の冒頭で、リフレクションの主な利点の1つは、操作中にオブジェクトタイプの情報を取得できることだと述べました。例を挙げて詳細に見てみましょう。
まず、 typeinfo.interfaceaパッケージの下に新しいAを作成します。
Package TypeInfo.interfacea;パブリックインターフェイスa {void f(); }次に、 typeinfo.packageaccessパッケージの下に新しいインターフェイスCを作成します。インターフェイスCインターフェイスAから継承され、テストのための他のいくつかの方法も作成しました。次の方法の権限は異なることに注意してください。
Package TypeInfo.PackageAcces; Import TypeInfo.interfacea.a;クラスCは{public void f(){system.out.println( "public cf()"); } public void g(){system.out.println( "public cg()"); }保護されたvoid v(){system.out.println( "Protected Cv()"); } void u(){system.out.println( "package cu()"); } private void w(){system.out.println( "private cw()"); }} public class hiddenc {public static a makea(){return new c(); }} callHiddenMethod()メソッドでは、いくつかの新しいAPIを使用します。ここでは、 getDeclaredMethod()使用して、クラスクラスがメソッド名に従ってオブジェクトを参照するメソッドを取得し、 invoke()メソッドを呼び出すことでオブジェクトの関連メソッドをトリガーできます。
Package TypeInfo; Import TypeInfo.interfacea.a; Import TypeInfo.packageaccess.hiddenc; Import Java.lang.Lang.Reflect.Method; public class hiddenimplementation {public static void main(String [] args)スロー例外{a = hiddenc.makea(); af(); system.out.println(a.getclass()。getname()); //おっと!反射により、g():callhiddenmethod(a、 "g")を呼び出すことができます。 //アクセスしにくい方法でさえ! callhiddenmethod(a、 "u"); CallhiddenMethod(a、 "v"); CallhiddenMethod(a、 "w"); } static void callhiddenmethod(object a、string methodname)スロー例外{method g = a.getclass()。 g.SetAccessible(true); g.invoke(a); }}出力の結果から、それがpublic 、 default 、 protect 、またはpricateメソッドであるかどうかにかかわらず、リフレクションクラスを通じて自由に呼び出すことができることがわかります。もちろん、私たちは反射の強力な力を示すためだけであり、この手法は実際の開発では推奨されません。
public cf()typeinfo.packageaccess.cpublic cg()パッケージCu()保護されたCv()private cw()private cw()
次のビジネスシナリオがあります。一般的なコレクションクラスList<Class<? extends Pet>> 。このコレクションクラスには、特定のPetの数を数える必要があります。 Javaジェネリック消去のため、 List<? extends Pet>コンパイラが静的タイプチェックを行った後、JVMは実行中にコレクション内のすべてのオブジェクトをPetとして扱うため、 List<? extends Pet>が、 Pet Catか犬かDogを表すかどうかはわかりません。 PS:一般的な消去について:前の記事で詳細な説明があります。興味のある友達は見ることができます。
上記の例を実装するには、最初にいくつかのクラスを定義します。
パブリッククラスのペットは個々の{public pet(string name){super(name); } public pet(){super(); }} public class catはペットを拡張します{public cat(string name){super(name); } public cat(){super(); }} public class dogはペットを拡張します{public dog(string name){super(name); }} public class egyptianmauはcat {public egyptianmau(string name){super(name); } public egyptianmau(){super(); }} public class muttはdog {public mutt(string name){super(name); } public mutt(){super(); }}上のPetクラスはIndividualから継承します。 Individualクラスの実装はもう少し複雑です。 Comparableインターフェイスを実装し、クラスの比較ルールを再定義しました。よく理解していなければ、それは問題ではありません。私たちはそれを抽出したので、実装の原則を理解していないかどうかは関係ありません。
パブリッククラスの個人実装comparable <sidult> {private static long counter = 0;プライベートファイナルロングID = counter ++;プライベート文字列名; //名前はオプションのpublic個人(文字列名){this.name = name; } public個人(){} public string toString(){return getClass()。getSimplename() +(name == null? "": "" + name); } public long id(){return id; } public boolean equals(object o){return o instance of個人&& id ==((個人)o).id; } public int hashcode(){int result = 17; if(name!= null){result = 37 * result + name.hashcode(); } result = 37 * result +(int)id;返品結果; } public int compareto(個人のarg){//クラス名で比較first:string first = getClass()。getSimplename(); string argfirst = arg.getclass()。getsimplename(); int firstCompare = first.compareto(argfirst); if(firstCompare!= 0){return firstCompare; } if(name!= null && arg.name!= null){int decondarycompare = name.compareto(arg.name); if(secendcompare!= 0){return sivingrouncompare; }} return(arg.id <id?-1:(arg.id == id?0:1)); }}以下は、抽象クラスのPetCreatorです。将来的には、 arrayList()メソッドを呼び出すことにより、関連するPetクラスのコレクションを直接取得できます。ここでは、上記で言及しなかったnewInstance()メソッドを使用します。クラスクラスが実際に言及しているクラスのインスタンスを返します。これはどういう意味ですか?たとえば、 new Dog().getClass().newInstance()およびDirect new Dog()を宣言することは同等です。
public abstract class petcreator {private random rand = new Random(47); //作成するペットのさまざまなgetTypesのリスト:パブリックアブストラクトリスト<クラス<? PETを拡張>> getTypes(); public Pet randompet(){// 1つのランダムPET int n = rand.nextint(getTypes()。size()); try {return getTypes()。get(n).newinstance(); } catch(instantiationexception e){new new runtimeexception(e); } catch(Illegalaccessexception e){新しいruntimeexception(e); }} public pet [] createarray(int size){pet [] result = new Pet [size]; for(int i = 0; i <size; i ++){result [i] = randompet(); } return result; } public ArrayList <Pet> arrayList(int size){arrayList <pet> result = new ArrayList <Pet>(); collections.addall(result、createarray(size));返品結果; }}次に、上記の抽象クラスを実装し、次のコードを説明しましょう。次のコードでは、 allTypesには上記のすべてのクラスが含まれている2つのコレクションクラス、 allTypesとtypesを宣言しますが、特定のタイプは実際にはMuttとEgypianMauという2つのタイプのみであるため、 new必要なペットはtypesに含まれるタイプです。将来的には、 getTypes()を呼び出すことにより、 typesに含まれるタイプを取得できます。
Public Class LiteralPetCreatorは、PetCreatorを拡張します{@suppresswarnings( "Unchecked")public static final list <class <? PET >> alltypes = collections.unmodifiablelist(arrays.aslist(pet.class、dog.class、cat.class、mutt.class、egyptianmau.class));プライベート静的最終リスト<クラス<? PET >> TYPES = AllTypes.sublist(alltypes.indexof(mutt.class)、alltypes.size());パブリックリスト<クラス<? PET >> getTypes(){return Types; }}全体的なロジックが完了し、最後に、セット内の関連するPetクラスの数をカウントするために使用されるTypeCounterクラスを実装します。 isAssignalbeFrom()メソッドを説明します。これは、反射クラスが反射クラスのサブクラスまたは間接サブクラスであると判断することができます。名前が示すように、 getSuperclass()反射クラスの親クラスを取得することです。
パブリッククラスのタイプカウンターはhashmap <class <?>、integer> {private class <?> baseTypeを拡張します。 public Typecounter(class <?> baseType){this.baseType = baseType; } public void count(object obj){class <?> type = obj.getClass(); if(!baseType.isassignablefrom(type)){throw new runtimeException(obj + "secorrect inge" + type + "は、" + baseTypeのタイプまたはサブタイプである必要があります); } countclass(type); } private void countclass(class <?> type){integer数量= get(type); put(type、数量== null?1:数量 + 1); class <?> superclass = type.getsuperclass(); if(superclass!= null && basetype.isassignablefrom(superclass)){countclass(superclass); }} @Override public String toString(){stringbuilder result = new StringBuilder( "{"); for(map.entry <class <?>、integer> pair:entryset()){result.append(pair.getKey()。getsimplename()); result.append( "="); result.append(pair.getValue()); result.append( "、"); } result.delete(result.length()-2、result.length()); result.append( "}"); return result.toString(); }}要約します
上記は、Java反射メカニズムのコード共有の例に関するこの記事のすべての内容であり、すべての人に役立つことを願っています。興味のある友達は引き続きこのサイトを参照できます:
Javaプログラミングと印刷ショッピングレシートの実装コード
Javaの参照と動的プロキシの実装の詳細な説明
月食の簡単なコード共有を実装するためのJavaプログラミング
欠点がある場合は、それを指摘するためにメッセージを残してください。このサイトへのご支援をありがとうございました!