JAvaプログラミング:java反射メカニズムの原理事例の詳細


本文は実例の説明の方式を採用してjavaの反射の原理と使用のシーンを生き生きと説明しました.
このリンクは次のとおりです.http://blog.csdn.net/xiong_it/article/details/46409875
この文章は依然として小さい例を采用して说明して、私がずっと感じているため、例の駆动は最も良くて、さもなくば理论だけを见て、见ても分からないで、しかしみんなが文章を読んだ后で、振り返って理论を见て、もっと良い理解があることを提案します.
以下、本文を開始します.
【ケース1】1つのオブジェクトから完全なパッケージ名とクラス名を取得
package Reflect;
 
/**
 *                 
 * */
class Demo{
    //other codes...
}
 
class hello{
    public static void main(String[] args) {
        Demo demo=new Demo();
        System.out.println(demo.getClass().getName());
    }
}

【運転結果】:Reflect.Demo
すべてのクラスのオブジェクトはクラスのインスタンスです.
【ケース2】クラスオブジェクトのインスタンス化
package Reflect;
class Demo{
    //other codes...
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo1=null;
        Class<?> demo2=null;
        Class<?> demo3=null;
        try{
            //          
            demo1=Class.forName("Reflect.Demo");
        }catch(Exception e){
            e.printStackTrace();
        }
        demo2=new Demo().getClass();
        demo3=Demo.class;
         
        System.out.println("      "+demo1.getName());
        System.out.println("      "+demo2.getName());
        System.out.println("      "+demo3.getName());
         
    }
}

【運転結果】:
クラス名   Reflect.Demo
クラス名   Reflect.Demo
クラス名   Reflect.Demo
【ケース3】Classによる他のクラスのオブジェクトのインスタンス化
インスタンス化されたオブジェクトをパラメトリックなしで構築する
package Reflect;
 
class Person{
     
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString(){
        return "["+this.name+"  "+this.age+"]";
    }
    private String name;
    private int age;
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Person per=null;
        try {
            per=(Person)demo.newInstance();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        per.setName("Rollen");
        per.setAge(20);
        System.out.println(per);
    }
}

【運転結果】:
[Rollen  20]
ただし、Personのデフォルトの非パラメトリックコンストラクション関数をキャンセルすると、たとえばパラメータのあるコンストラクション関数を1つだけ定義すると、エラーが発生します.
たとえば、コンストラクション関数を定義します.
次に、上記のプログラムを実行し続けると、次のように表示されます.
java.lang.InstantiationException: Reflect.Person
    at java.lang.Class.newInstance0(Class.java:340)
    at java.lang.Class.newInstance(Class.java:308)
    at Reflect.hello.main(hello.java:39)
Exception in thread "main" java.lang.NullPointerException
    at Reflect.hello.main(hello.java:47)

だから皆さんは後でClassを使って他のクラスのオブジェクトをインスタンス化する時、必ず自分で無参の構造関数を定義しなければなりません.
 
【ケース】Classで他のクラスのコンストラクション関数を呼び出す (クラスによって他のクラスのオブジェクトを作成することもできます)
package Reflect;
 
import java.lang.reflect.Constructor;
 
class Person{
     
    public Person() {
         
    }
    public Person(String name){
        this.name=name;
    }
    public Person(int age){
        this.age=age;
    }
    public Person(String name, int age) {
        this.age=age;
        this.name=name;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString(){
        return "["+this.name+"  "+this.age+"]";
    }
    private String name;
    private int age;
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Person per1=null;
        Person per2=null;
        Person per3=null;
        Person per4=null;
        //         
        Constructor<?> cons[]=demo.getConstructors();
        try{
            per1=(Person)cons[0].newInstance();
            per2=(Person)cons[1].newInstance("Rollen");
            per3=(Person)cons[2].newInstance(20);
            per4=(Person)cons[3].newInstance("Rollen",20);
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(per1);
        System.out.println(per2);
        System.out.println(per3);
        System.out.println(per4);
    }
}

【運転結果】:
[null  0]
[Rollen  0]
[null  20]
[Rollen  20]
【ケース】クラスインプリメンテーションのインタフェースを返します.
package Reflect;
 
interface China{
    public static final String name="Rollen";
    public static  int age=20;
    public void sayChina();
    public void sayHello(String name, int age);
}
 
class Person implements China{
    public Person() {
         
    }
    public Person(String sex){
        this.sex=sex;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    @Override
    public void sayChina(){
        System.out.println("hello ,china");
    }
    @Override
    public void sayHello(String name, int age){
        System.out.println(name+"  "+age);
    }
    private String sex;
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        //       
        Class<?> intes[]=demo.getInterfaces();
        for (int i = 0; i < intes.length; i++) {
            System.out.println("        "+intes[i].getName());
        }
    }
}

【運転結果】:
実装されたインタフェース   Reflect.China
(以下のいくつかの例では、この例のPersonクラスが用いられるので、紙面を節約するために、ここではPersonのコード部分を貼り付けず、メインクラスhelloのコードのみを貼り付ける)
【ケース】:他のクラスの親を取得
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        //    
        Class<?> temp=demo.getSuperclass();
        System.out.println("      :   "+temp.getName());
    }
}

【運転結果】
継承された親は次のとおりです.   java.lang.Object
【ケース】:他のクラスのすべてのコンストラクション関数を取得
この例では、プログラムの先頭にimportを追加する必要があります. java.lang.reflect.*;
次に、プライマリクラスを次のように記述します.
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Constructor<?>cons[]=demo.getConstructors();
        for (int i = 0; i < cons.length; i++) {
            System.out.println("    :  "+cons[i]);
        }
    }
}

【運転結果】:
構築方法:  public Reflect.Person()
構築方法:  public Reflect.Person(java.lang.String)
しかし、注意深い読者は、上の構造関数にpublicがないことを発見します. またはprivateのような修飾子
【ケース】:次の例では、修飾子を取得します.
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("Reflect.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Constructor<?>cons[]=demo.getConstructors();
        for (int i = 0; i < cons.length; i++) {
            Class<?> p[]=cons[i].getParameterTypes();
            System.out.print("    :  ");
            int mo=cons[i].getModifiers();
            System.out.print(Modifier.toString(mo)+" ");
            System.out.print(cons[i].getName());
            System.out.print("(");
            for(int j=0;j<p.length;++j){
                System.out.print(p[j].getName()+" arg"+i);
                if(j<p.length-1){
                    System.out.print(",");
                }
            }
            System.out.println("){}");
        }
    }
}

【運転結果】:
構築方法:  public Reflect.Person(){}
構築方法:  public Reflect.Person(java.lang.String arg1){}
时には一つの方法に異常があるかもしれませんが、ほほほ.次に、
【運転結果】:
public java.lang.String  getSex ()
public void  setSex (java.lang.String arg0)
public void  sayChina ()
public void  sayHello (java.lang.String arg0,int arg1)
public final native void  wait (long arg0) throws java.lang.InterruptedException
public final void  wait () throws java.lang.InterruptedException
public final void  wait (long arg0,int arg1) throws java.lang.InterruptedException
public boolean  equals (java.lang.Object arg0)
public java.lang.String  toString ()
public native int  hashCode ()
public final native java.lang.Class  getClass ()
public final native void  notify ()
public final native void  notifyAll ()

【ケース】次に他のクラスのすべての属性を取得しましょう.最後にこれらを整理します.つまりclassを通じてクラスのすべてのフレームワークを取得します.
class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("===============    ========================");
        //          
        Field[] field = demo.getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            //      
            int mo = field[i].getModifiers();
            String priv = Modifier.toString(mo);
            //     
            Class<?> type = field[i].getType();
            System.out.println(priv + " " + type.getName() + " "
                    + field[i].getName() + ";");
        }
        System.out.println("===============            ========================");
        //               
        Field[] filed1 = demo.getFields();
        for (int j = 0; j < filed1.length; j++) {
            //      
            int mo = filed1[j].getModifiers();
            String priv = Modifier.toString(mo);
            //     
            Class<?> type = filed1[j].getType();
            System.out.println(priv + " " + type.getName() + " "
                    + filed1[j].getName() + ";");
        }
    }
}

【運転結果】:
===============    ========================
private java.lang.String sex;
===============            ========================
public static final java.lang.String name;
public static final int age;

【ケース】他のクラスのメソッドを反射的に呼び出すこともできます.
class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        try{
            //  Person   sayChina  
            Method method=demo.getMethod("sayChina");
            method.invoke(demo.newInstance());
            //  Person sayHello  
            method=demo.getMethod("sayHello", String.class,int.class);
            method.invoke(demo.newInstance(),"Rollen",20);
             
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

【運転結果】:
hello ,china
Rollen  20
【ケース】他のクラスのsetメソッドとgetメソッドを呼び出す
class hello {
    public static void main(String[] args) {
        Class<?> demo = null;
        Object obj=null;
        try {
            demo = Class.forName("Reflect.Person");
        } catch (Exception e) {
            e.printStackTrace();
        }
        try{
         obj=demo.newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        setter(obj,"Sex"," ",String.class);
        getter(obj,"Sex");
    }
 
    /**
     * @param obj
     *                 
     * @param att
     *                 
     * */
    public static void getter(Object obj, String att) {
        try {
            Method method = obj.getClass().getMethod("get" + att);
            System.out.println(method.invoke(obj));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    /**
     * @param obj
     *                 
     * @param att
     *                 
     * @param value
     *                
     * @param type
     *                 
     * */
    public static void setter(Object obj, String att, Object value,
            Class<?> type) {
        try {
            Method method = obj.getClass().getMethod("set" + att, type);
            method.invoke(obj, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}// end class

【運転結果】:

 【ケース】反射操作による属性
class hello {
    public static void main(String[] args) throws Exception {
        Class<?> demo = null;
        Object obj = null;
 
        demo = Class.forName("Reflect.Person");
        obj = demo.newInstance();
 
        Field field = demo.getDeclaredField("sex");
        field.setAccessible(true);
        field.set(obj, " ");
        System.out.println(field.get(obj));
    }
}// end class

【ケース】反射によって配列の情報を取得して修正する:
import java.lang.reflect.*;
class hello{
    public static void main(String[] args) {
        int[] temp={1,2,3,4,5};
        Class<?>demo=temp.getClass().getComponentType();
        System.out.println("    : "+demo.getName());
        System.out.println("      "+Array.getLength(temp));
        System.out.println("        : "+Array.get(temp, 0));
        Array.set(temp, 0, 100);
        System.out.println("            : "+Array.get(temp, 0));
    }
}

【運転結果】:
配列タイプ: int
配列の長さ  5
配列の最初の要素:1
修正後の配列の最初の要素は次のとおりです. 100
【ケース】反射による配列サイズの変更
class hello{
    public static void main(String[] args) {
        int[] temp={1,2,3,4,5,6,7,8,9};
        int[] newTemp=(int[])arrayInc(temp,15);
        print(newTemp);
        System.out.println("=====================");
        String[] atr={"a","b","c"};
        String[] str1=(String[])arrayInc(atr,8);
        print(str1);
    }
     
    /**
     *       
     * */
    public static Object arrayInc(Object obj,int len){
        Class<?>arr=obj.getClass().getComponentType();
        Object newArr=Array.newInstance(arr, len);
        int co=Array.getLength(obj);
        System.arraycopy(obj, 0, newArr, 0, co);
        return newArr;
    }
    /**
     *   
     * */
    public static void print(Object obj){
        Class<?>c=obj.getClass();
        if(!c.isArray()){
            return;
        }
        System.out.println("     : "+Array.getLength(obj));
        for (int i = 0; i < Array.getLength(obj); i++) {
            System.out.print(Array.get(obj, i)+" ");
        }
    }
}

【運転結果】:
配列の長さ: 15
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
配列の長さ: 8
a b c null null null null null
ダイナミックエージェント
【ケース】まず、クラス・ローダの入手方法を見てみましょう.
class test{
     
}
class hello{
    public static void main(String[] args) {
        test t=new test();
        System.out.println("      "+t.getClass().getClassLoader().getClass().getName());
    }
}

【プログラム出力】:
クラスローダ  sun.misc.Launcher$AppClassLoader
実はjavaには3種類のクラスローダがあります.
1)Bootstrap ClassLoader このローダはc++で記述されており,一般開発では珍しい.
2)Extension ClassLoader 拡張クラスのロードに使用されます.一般的にはjrelibextディレクトリのクラスに対応します.
3)AppClassLoader classpathで指定したクラスをロードするのは、最も一般的なローダです.javaのデフォルトのローダでもあります.
動的エージェントを完了するには、まずInvocationHandlerインタフェースのサブクラスを定義し、エージェントの具体的な操作を完了する必要があります.
package Reflect;
import java.lang.reflect.*;
 
//      
interface Subject {
    public String say(String name, int age);
}
 
//       
class RealSubject implements Subject {
    @Override
    public String say(String name, int age) {
        return name + "  " + age;
    }
}
 
class MyInvocationHandler implements InvocationHandler {
    private Object obj = null;
 
    public Object bind(Object obj) {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
                .getClass().getInterfaces(), this);
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object temp = method.invoke(this.obj, args);
        return temp;
    }
}
 
class hello {
    public static void main(String[] args) {
        MyInvocationHandler demo = new MyInvocationHandler();
        Subject sub = (Subject) demo.bind(new RealSubject());
        String info = sub.say("Rollen", 20);
        System.out.println(info);
    }
}

【運転結果】:
Rollen  20
クラスのライフサイクル
クラスのコンパイルが完了したら、次のステップでクラスの使用を開始する必要があります.クラスを使用する場合は、JVMから離れられないに違いありません.プログラム実行中にJVMはマウント、リンク、初期化の3つのステップで完了します.
クラスのマウントはクラス・ローダによって行われ、ローダは.classファイルのバイナリ・ファイルをJVMのメソッド領域に読み込み、このクラスを記述するjava.lang.Classオブジェクトをスタック領域に作成します.データをカプセル化するために使用します. ただし、同じクラスはクラスローダにロードされる前にのみ
リンクとは,バイナリデータを実行可能な状態に組み立てることである.
 
リンクはチェック、準備、解析の3段階に分かれています
通常、このバイナリファイルが現在のJVM(バージョン)に適しているかどうかを確認するために使用されます.
静的メンバーにメモリ領域を割り当てる準備です.デフォルト設定
解析とは、すべてのシンボル参照が実行プログラムによって使用されるまで、定数プール内のコードを直接参照として変換するプロセスです(完全な対応関係が確立されます).
完了すると、タイプも初期化され、初期化後にクラスのオブジェクトが正常に使用され、1つのオブジェクトが使用されなくなるまでゴミが回収されます.スペースを解放します.
クラスオブジェクトへの参照がない場合はアンインストールされ、クラスのライフサイクルが終了します.
工場モードでの反射の使用
まず、反射しない場合の工場モードを見てみましょう.
http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144851.html
/**
 * @author Rollen-Holt           
 */
 
interface fruit{
    public abstract void eat();
}
 
class Apple implements fruit{
    public void eat(){
        System.out.println("Apple");
    }
}
 
class Orange implements fruit{
    public void eat(){
        System.out.println("Orange");
    }
}
 
//      
//                                 
class Factory{
    public static fruit getInstance(String fruitName){
        fruit f=null;
        if("Apple".equals(fruitName)){
            f=new Apple();
        }
        if("Orange".equals(fruitName)){
            f=new Orange();
        }
        return f;
    }
}
class hello{
    public static void main(String[] a){
        fruit f=Factory.getInstance("Orange");
        f.eat();
    }
 
}

これにより、サブクラスを追加するときに、ファクトリクラスを変更する必要があります.サブクラスを追加しすぎると、変更が多くなります.
反射メカニズムの利用を見てみましょう
package Reflect;
 
interface fruit{
    public abstract void eat();
}
 
class Apple implements fruit{
    public void eat(){
        System.out.println("Apple");
    }
}
 
class Orange implements fruit{
    public void eat(){
        System.out.println("Orange");
    }
}
 
class Factory{
    public static fruit getInstance(String ClassName){
        fruit f=null;
        try{
            f=(fruit)Class.forName(ClassName).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}
class hello{
    public static void main(String[] a){
        fruit f=Factory.getInstance("Reflect.Apple");
        if(f!=null){
            f.eat();
        }
    }
}

これで、任意の複数のサブクラスを追加しても、ファクトリクラスは変更する必要はありません.
 
上記の愛は,反射によってインタフェースのインスタンスを取得することができるが,完全なパケットとクラス名を伝達する必要がある.また、ユーザーは、1つのインタフェースに使用可能なサブクラスがいくつあるかを知ることができません.そのため、プロパティファイルの形式で必要なサブクラスを構成します.
次に、 プロパティ・ファイルを結合したファクトリ・モード
まずfruit.propertiesのリソースファイルを作成し、
内容は次のとおりです.
apple=Reflect.Apple
orange=Reflect.Orange

次に、プライマリクラスコードを記述します.
package Reflect;
 
import java.io.*;
import java.util.*;
 
interface fruit{
    public abstract void eat();
}
 
class Apple implements fruit{
    public void eat(){
        System.out.println("Apple");
    }
}
 
class Orange implements fruit{
    public void eat(){
        System.out.println("Orange");
    }
}
 
//       
class init{
    public static Properties getPro() throws FileNotFoundException, IOException{
        Properties pro=new Properties();
        File f=new File("fruit.properties");
        if(f.exists()){
            pro.load(new FileInputStream(f));
        }else{
            pro.setProperty("apple", "Reflect.Apple");
            pro.setProperty("orange", "Reflect.Orange");
            pro.store(new FileOutputStream(f), "FRUIT CLASS");
        }
        return pro;
    }
}
 
class Factory{
    public static fruit getInstance(String ClassName){
        fruit f=null;
        try{
            f=(fruit)Class.forName(ClassName).newInstance();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return f;
    }
}
class hello{
    public static void main(String[] a) throws FileNotFoundException, IOException{
        Properties pro=init.getPro();
        fruit f=Factory.getInstance(pro.getProperty("apple"));
        if(f!=null){
            f.eat();
        }
    }
}

【実行結果】:Apple本リンク:http://blog.csdn.net/xiong_it/article/details/46409875
転載先:http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html