JAVA反射機制

所謂的反射機制就是java語言在運行時擁有的一項自觀的能力。通過這種能力可以徹底地瞭解自身的情況爲下一步的動作做準備。下面介紹java的反射機制。

    Java的反射機制的實現要藉助於4個類:ClassConstructorFieldMethod,其中Class代表的是類對象,Constructor代表類的構造器對象,Field代表類的屬性對象,Method代表類的方法對象。通過這四個對象我們可以粗略看到一個類的各個組成部分。

    Class:

程序運行時,java運行時系統會對所有的對象進行運行時類型的處理。這項信息記錄了每個對象所屬的類,虛擬機通常使用運行時類型信息選擇正確的方法來執行。我們可以藉助Object類中定義的getClass()方法要得到指定對象的類對象,然後通過分析這個對象得到我們想要的信息,而Class本身又有很多重要的方法,此處重點將和Constructor,Field,Method類有關係的方法:

ü  Class.forName(“類名”) 表示載入指定的類,調用getDeclaredMethods

獲取這個類中定義的方法列表

    實例:

package com.yilong.reflect;

import java.lang.reflect.Method;

public class Test1 {

    public static void main(String[] args) {

       try {

           Class c = Class.forName(args[0]);

           Method m[] = c.getDeclaredMethods();

           for(int i=0; i<m.length; i++) {

              System.out.println(m[i].toString());

              }

       } catch(Throwable e) {

              e.printStackTrace();

       }

    }

}

    執行方法:

    編譯:javac –d . Test1.java

    運行:java com.yilong.reflect.Test1 java.util.ArrayList

    Constructor:

    Constructor getConstructor(Class[] params) – 獲得使用特殊的參數類型的公共構造函數;

    Constructor[] getConstructors() – 獲得類的所有公共構造函數;

    Constructor getDeclaredConstructor(Class[] params) – 獲得使用特定參數類型的構造函數(上面是公共)

    Constructor[] getDeclaredConstructors() – 獲得類的所有構造函數(上面是公共”);

    Field:

    Field getField(String name) – 獲得命名的公共字段;

    Field[] getFields() – 獲得類的所有公共字段;

    Field getDeclaredField(String name) – 獲得類聲明的命名的字段;

    Fidld[] getDeclaredFields() – 獲得類聲明的所有字段。

    Method:

   Method getMethods(String name, Class[] params) – 使用特定的參數類型,獲得命名的公共方法;

    Method[] getMethods() – 獲得類的所有公共方法;

    Method getDeclaredMethod(String name, Class[] params) – 使用特定的參數類型,獲得聲明的命名的方法;

    Method[] getDeclaredMethods() – 獲得類聲明的所有的方法

    要向使用JAVAReflection,需要遵循三個步驟

第一步:獲得你想要操作的類的java.lang.Class對象。在運行中的JAVA程序中,用

java.lang.Class類來描述類和接口等;

下面是獲得Class對象的一些方法:

*  Class c = Class.forName(“java.lang.String”);

*  Class c = int.class;

*  Class c = Integer.TYPE;

第二步:調用諸如getDeclaredMethods的方法,取得該類中定義的所有方法的列表;

第三步:使用reflectionAPI來操作這些信息。

    下面是一些具體的實例:

   Java中使用Class.forName(“”).newInstance();對對象進行實例化,同時還需要掌握對其對象方法的調用方法。

    下面結合具體例子進行分析:

Ø  文件com.yilong.test.instance.NewClass.java

package com.yilong.test.instance;

public class NewClass {

  public boolean method() {

     System.out.println("ok!");

     return true;

  }

}

Ø  文件com.yilong.test.instance.Main.java

package com.yilong.test.instance;

import java.lang.reflect.Method;

public class Main {

  public static void main(String[] args) throws Exception {

     Object clazz = Class

.forName("com.yilong.test.instance.NewClass")

.newInstance();

     Method method = clazz.getClass().getMethod("method");

     Class returntype = method.getReturnType();

     method.invoke(clazz);

     System.out.println(method.getName() + "|"

+ returntype.getName());

  }

}

注意事項1:上面的getMethod()方法只適用於調用的方法沒有參數的情況,如果方法要傳遞參數,還需要指定參數的類型(因爲有重載),對應地,method.invoke()方法也是要傳遞具體的參數值的。

ü  public Method getMethod(String name,  Class<?>… parameterTypes)

           throws NoSuchMethodException,SecurityException

ü  public Object invoke(Object obj, Object... args)

throws IllegalAccessException,

IllegalArgumentException,  InvocationTargetException

ü  另外,還有一個重載的方法是可以拿到一個類裏定義的所有的方法:

Class clazz = Class.forName("com.yilong.test.instancemethod.NewClass");

Method[] methods = clazz.getMethods();

//clazz只是拿到該類,還沒實例化,如果實例化了,那麼就要調用//newInstance.getClass().getMethods();

    下面是囊括了比較多的情況的例子

Ø  文件NewClass.java

package com.yilong.test.instance;

public class NewClass {

  public void method0() {

     System.out.print("0個參數的方法調用成功!");

  }

  public boolean method1(int id) {

     System.out.print("1個參數的方法調用成功!");

     return true;

  }

  public String method2(int id, String name) {

     System.out.print("2個參數的方法調用成功!");

     return "success";

  }

  public int method3(String[] strs) {

     System.out.print("參數爲數組的方法調用成功!");

     return 1;

  }

}

Ø  文件Main.java

package com.yilong.test.instance;

import java.lang.reflect.Method;

public class Main {

  public static void main(String[] args) throws Exception {

     Object clazz = Class.forName

("com.yilong.test.instance.NewClass").newInstance();

     //調用0個參數的方法

     Method method0 = clazz.getClass().getMethod("method0");

     Class returntype0 = method0.getReturnType();

     method0.invoke(clazz);

     System.out.println("  --  " + method0.getName() + "|" +

returntype0.getName());

     //調用1個參數的方法

     Class[] parameterTypes1 = new Class[1];

     parameterTypes1[0] = int.class;

     Method method1 = clazz.getClass().getMethod("method1",

parameterTypes1);

     Class returntype1 = method1.getReturnType();

     method1.invoke(clazz, 1);

     System.out.println("  --  " + method1.getName() + "|" +

returntype1.getName());

     //調用2個參數的方法

     Class[] parameterTypes2 = new Class[2];

     parameterTypes2[0] = int.class;

     parameterTypes2[1] = String.class;

     Method method2 = clazz.getClass().getMethod("method2",

parameterTypes2);

     Class returntype2 = method2.getReturnType();

     method2.invoke(clazz, 2, "ok");

     //或者

     Object[] arguments = new Object[2];

     arguments[0] = 2;

     arguments[1] = "ok";

     method2.invoke(clazz, arguments);

     System.out.println("  --  " + method2.getName() + "|" +

returntype2.getName());

     //調用參數爲數組的方法

     Class[] parameterType3 = new Class[1];

     parameterType3[0] = String[].class;

     Method method3 = clazz.getClass().getMethod("method3",

parameterType3);

     Class returntype3 = method3.getReturnType();

     Object[] arguments3 = new Object[1];

     String[] strs = new String[2];

     strs[0] = "aa";

     strs[1] = "bb";

     arguments[0] = strs;

     method3.invoke(clazz, arguments3);

     System.out.println("  --  " + method3.getName() + "|" +

returntype3.getName());

  }

}

注意事項2:通過Class.forName("com.yilong.test.instance.NewClass");方法得到的Class只能是放在classPath下面的class文件生成的,即對應項目中的bin目錄下的文件,也就是說前面的目錄已經默認是項目根路徑 + bin”。而通過netURL方式new出來得到Class則不一定,具體實例如下:

System.out.println(System.getProperty("user.dir"));

//D:/MyEclipse/Proxy1

URL[] urls = new URL[] {new URL("file:/" +

System.getProperty("user.dir") + "/src")};

URLClassLoader ul = new URLClassLoader(urls);

Class c = ul.loadClass("com.yilong.designpattern.proxy.TimeProxy");

System.out.println(c);

項目中目錄狀態如下:

 

注意事項3:上述的newInstance()方法只能實例化沒有參數的構造方法,要實例化有參數的構造方法,可以:

Constructor ctr = c.getConstructor(Moveable.class);//指定參數類型

Moveable m = (Moveable)ctr.newInstance(new Tank());//傳遞參數

Ø  文件Main.java

package com.yilong.test.instancemethod;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

public class Main {

    public static void main(String[] args) {

       try {

           Class clazz = Class.forName

("com.yilong.test.instancemethod.NewClass");

           System.out.println(clazz);

           //調用1個參數的構造方法

           Constructor ctr1 = clazz.getConstructor(int.class);

           System.out.println(ctr1);

           ctr1.newInstance(1);

               //調用2個參數的構造方法

Constructor ctr2 = clazz.getConstructor(int.class,

String.class);

           System.out.println(ctr2);

           ctr2.newInstance(2, "ok");

       } catch (ClassNotFoundException e) {

           e.printStackTrace();

       } catch (IllegalAccessException e) {

           e.printStackTrace();

       } catch (InstantiationException e) {

           e.printStackTrace();

       } catch (SecurityException e) {

           e.printStackTrace();

       } catch (NoSuchMethodException e) {

           e.printStackTrace();

       } catch (IllegalArgumentException e) {

           e.printStackTrace();

       } catch (InvocationTargetException e) {

           e.printStackTrace();

       }

    }

}

Ø  文件NewClass.java

package com.yilong.test.instancemethod;

public class NewClass {

    public NewClass(int id) {

       System.out.println("1個參數的構造方法調用成功!");

    }

    public NewClass(int id, String str) {

       System.out.println("2個參數的構造方法調用成功!");

    }

    public void method(String[] strs, int i) {

       System.out.println("success!");

    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章