ダークホースプログラマー-----Java高級特性-----反射

19638 ワード

ダークホースプログラマー–Javaの高級特性———反射
——-androidトレーニング、javaトレーニング、あなたとの交流を期待しています。———
一.概要
Java反射はJava言語の重要な特徴であり、Javaが具体的に「動的性」を示す。このメカニズムは、プログラムが実行中にReflect APIを通して既知の名前のclassの内部情報を取得することを可能にし、そのmodifiers(public、staticなど)、superclass(例えばObject)、実現されたinterfaces(例えばSerializable)、fieldsおよびmethodsのすべての情報を含み、実行時にコンテンツを変更したり、fieldsを呼び出したりすることができます。Javaプログラムは、実行時に名前を知るclassをロードし、その完全な構造を知ることができます(ただし、methods定義は含まれません)。そして、そのオブジェクトエンティティを生成したり、fieldsに値を設定したり、methodsを喚起したりします。この「classを見抜く」能力(the ability of the program to exmine itself)はintrosspection(内省、内観、反省)と呼ばれています。Reflection(反射)とintrosspection(内省)はよく併記されている2つの用語です。
二.Java反射のAPI
反射でよく使われるいくつかのクラスは、次のように示されています。java.langパッケージでは、クラスJavaを代表して、いくつかのクラスのオブジェクトを生成しても、これらのオブジェクトは同じクラスのオブジェクトJava.lang.reflectパッケージに対応します。一つの方法は、Methodオブジェクト-Costructorクラスに対応しています。クラスを表す構造方法–Arayクラス:動的に配列を作成し、配列の要素にアクセスする静的方法を提供します。
三.JAVAを使った反射総合例
1.クラスのオブジェクトの取得と実装
//1.      Class   
//       :
//a)   Class   forName        (  :   +   ):
    Class> classType = Class.forName("java.lang.String");
//b)     +   class      :
     Class> c = String.class;
//c)        getClass      :
    String str = "test";
    Class> typeClass = str.getClass();


//2.          
//    :
//a)   Class     newInstance      (             ):
    Class> classType = Class.forName("java.lang.String");
    Object obj = = classType.newInstance();
//b)     Constructor         ,         newInstance (Object ... initargs)     :
    Class> classType = cus.getClass();
    Constructor con= classType.getConstructor(new Class[]{String.class,int.class});
    Object object= con.newInstance(new Object[]{cus.getName(),cus.getAge()});
                    Class[]{}   new Object[ ]{} ,     a)    
2.prvateで修飾された方法と属性にアクセスする
public class Private  
{  
    private String name = "  ";  

    private String getName()  
    {  
        return name;  
    }  
}  
このクラスのprvateで修飾されたname値を「李四」に変更し、反射機構でgetNameメソッドを呼び出し、修正された値を返します。
package com.wangzhuo.reflect;  

import java.lang.reflect.Constructor;  
import java.lang.reflect.Field;  
import java.lang.reflect.Method;  

public class PrivateTest  
{  
    public static void main(String[] args)throws Exception  
    {  
        //  Private  Class    
        Class> classType = Class.forName("com.wangzhuo.reflect.Private");  

         //          Constructor    
        Constructor con = classType.getDeclaredConstructor(new Class[]{});  

         //  Private     
        Object object =con.newInstance(new Object[]{});  

       //  Private  name     Field    
        Field field = classType.getDeclaredField("name");  

        //    java        
        field.setAccessible(true);  

        //         
        Object str = field.get(object);  

        System.out.println("    name  :"+(String)str);  

        // name      
        field.set(object, "  ");  

       //  getName     Method    
        Method getNameMethod = classType.getDeclaredMethod("getName", new Class[]{});  

        //    java        
        getNameMethod.setAccessible(true);  

        //    ,     
        Object  o = getNameMethod.invoke(object, new Object[]{});  
        System.out.println("    name  :"+(String)o);  
    }  
}  
3.運転時に複製対象(重要)ReflectTester類は、Reflection APIの基本的な使用方法をさらに示しています。Reflect Testerクラスには、パラメータobjectと同じタイプのオブジェクトを作成して、objectオブジェクトオブジェクトの中のすべての属性を新規作成の対象にコピーして返します。
public class ReflectTester {
    public Object copy(Object object) throws Exception {
        //        
        Class> classType = object.getClass();
        System.out.println("Class:" + classType.getName());

        //                 
        Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});

        //          
        Field fields[] = classType.getDeclaredFields();

        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];

            String fieldName = field.getName();
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            //         getXXX()     
            String getMethodName = "get" + firstLetter + fieldName.substring(1);
            //         setXXX()     
            String setMethodName = "set" + firstLetter + fieldName.substring(1);

            //         getXXX()  
            Method getMethod = classType.getMethod(getMethodName, new Class[]{});
            //         setXXX()  
            Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()});

            //       getXXX()  
            Object value = getMethod.invoke(object, new Object[]{});
            System.out.println(fieldName + ":" + value);
            //        setXXX()  
            setMethod.invoke(objectCopy, new Object[]{value});
        }
        return objectCopy;
    }

    public static void main(String[] args) throws Exception {
        Customer customer = new Customer("Tom", 21);
        customer.setId(new Long(1));

        Customer customerCopy = (Customer) new ReflectTester().copy(customer);
        System.out.println("Copy information:" + customerCopy.getId() + " " + customerCopy.getName() + " "
                + customerCopy.getAge());
    }
}

class Customer {
    private Long id;

    private String name;

    private int age;

    public Customer() {
    }

    public Customer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    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;
    }
}

出力結果:
Class:com.langsin.reflection.Customer
id:1
name:Tom
age:21
Copy information:1 Tom 21
例四.運転時にfield内容を変更する
public class RefFiled {
    public double x;
    public Double y;

    public static void main(String args[]) throws NoSuchFieldException, IllegalAccessException {
        Class c = RefFiled.class;
        Field xf = c.getField("x");
        Field yf = c.getField("y");

        RefFiled obj = new RefFiled();

        System.out.println("   x=" + xf.get(obj));
        //    x 
        xf.set(obj, 1.1);
        System.out.println("   x=" + xf.get(obj));

        System.out.println("   y=" + yf.get(obj));
        //    y 
        yf.set(obj, 2.1);
        System.out.println("   y=" + yf.get(obj));
    }
}
実行結果:
   x=0.0
   x=1.1
   y=null
   y=2.1
例5.反射機構でオブジェクトを呼び出す方法
public class InvokeTester {
    public int add(int param1, int param2) {
        return param1 + param2;
    }

    public String echo(String msg) {
        return "echo: " + msg;
    }

    public static void main(String[] args) throws Exception {
        Class> classType = InvokeTester.class;
        Object invokeTester = classType.newInstance();

        // Object invokeTester = classType.getConstructor(new
        // Class[]{}).newInstance(new Object[]{});


        //  InvokeTester  add()  
        Method addMethod = classType.getMethod("add", new Class[]{int.class, int.class});
        //  invokeTester    add()  
        Object result = addMethod.invoke(invokeTester, new Object[]{new Integer(100), new Integer(200)});
        System.out.println((Integer) result);


        //  InvokeTester  echo()  
        Method echoMethod = classType.getMethod("echo", new Class[]{String.class});
        //  invokeTester   echo()  
        result = echoMethod.invoke(invokeTester, new Object[]{"Hello"});
        System.out.println((String) result);
    }
}
ルーチンInvokeTesterクラスのmain()方法では、反射機構を用いてInvokeTesterオブジェクトのadd()とecho()方法を呼び出す。
add()メソッドの2つのパラメータはintタイプで、add()メソッドを表すMethodオブジェクトを得るコードは以下の通りです。Method adMethod=clastType.getMethod(「add」、new Class[];Method類のinvoke(Object Obj,Object args[])方法で受信したパラメータは対象でなければなりません。パラメータがベースタイプのデータであれば、該当するパッケージタイプのオブジェクトに変換しなければなりません。invoke()メソッドの戻り値は常にオブジェクトであり、実際に呼び出された方法の戻りタイプがベースタイプのデータであれば、invoke()メソッドはそれを対応するパッケージタイプのオブジェクトに変換して返します。
本例では、InvokeTester類のadd()方法の2つのパラメータおよび返却値はいずれもintタイプであるにもかかわらず、add Methodオブジェクトのinvoke()メソッドを呼び出すと、Integerタイプのパラメータのみが伝達され、invoke()方法の返却タイプもIntegerタイプであり、Integer類はintベースタイプのパッケージクラスである:Object=addstrect.Mestinker.Medstindestinker。{new Integer(100)、new Integer(200)}、System.out.println(Integer)reult)//reultはIntegerタイプです。
六.動的作成とアクセス配列ArayTester 1の種類のmain()メソッドは、長さ10の文字列配列を作成し、次にインデックス位置5の要素を「hello」として設定し、インデックス位置5の要素の値を読み取ります。
public class ArrayTester1 {
    public static void main(String args[]) throws Exception {
        Class> classType = Class.forName("java.lang.String");
        //        10      
        Object array = Array.newInstance(classType, 10);
        //       5     "hello"
        Array.set(array, 5, "hello");
        //        5     
        String s = (String) Array.get(array, 5);
        System.out.println(s);
    }
}
ArayTester 2類のmain()メソッドは、5 x 10 x 15の整数配列を作成し、インデックス位置を[3][5][10]の要素の値を設定37とする。
public class ArrayTester2 {
    public static void main(String args[]) {
        int[] dims = new int[]{5, 10, 15};
        //                    。
        Object array = Array.newInstance(Integer.TYPE, dims);

        Object arrayObj = Array.get(array, 3);
        Class> cls = arrayObj.getClass().getComponentType();
        System.out.println(cls);

        arrayObj = Array.get(arrayObj, 5);
        Array.setInt(arrayObj, 10, 37);
        int arrayCast[][][] = (int[][][]) array;
        System.out.println(arrayCast[3][5][10]);
    }
}
この文章は参考にしたhttp://lavasoft.blog.51cto.com/62575/43218/ http://847353020-qq-com.iteye.com/blog/1003440