1、先看一下反射的概念:java
主要是指程序能夠訪問,檢測和修改它自己狀態或行爲的一種能力,並能根據自身行爲的狀態和結果,調整或修改應用所描述行爲的狀態和相關的語義。數據庫
反射是java中一種強大的工具,可以使咱們很方便的建立靈活的代碼,這些代碼能夠再運行時裝配,無需在組件之間進行源代碼連接。可是反射使用不當會成本很高!數組
2、反射機制的做用:安全
1,反編譯:.class-->.javaapp
2,經過反射機制訪問java對象的屬性,方法,構造方法等;工具
3、在這裏先看一下sun爲咱們提供了那些反射機制中的類:性能
java.lang.Class; 學習
java.lang.reflect.Constructor; java.lang.reflect.Field; this
java.lang.reflect.Method;spa
java.lang.reflect.Modifier;
4、具體功能實現:
一、反射機制獲取類有三種方法,咱們來獲取Employee類型
//第一種方式: Classc1 = Class.forName("Employee"); //第二種方式: //java中每一個類型都有class 屬性. Classc2 = Employee.class; //第三種方式: //java語言中任何一個java對象都有getClass 方法 Employeee = new Employee(); Classc3 = e.getClass(); //c3是運行時類 (e的運行時類是Employee)
二、建立對象:獲取類之後咱們來建立它的對象,利用newInstance:
Class c =Class.forName("Employee"); //建立此Class 對象所表示的類的一個新實例 Objecto = c.newInstance(); //調用了Employee的無參數構造方法.
3,獲取屬性:分爲全部的屬性和指定的屬性:
a,先看獲取全部的屬性的寫法:
//獲取整個類 Class c = Class.forName("java.lang.Integer"); //獲取全部的屬性? //定義可變長的字符串,用來存儲屬性 StringBuffer sb = new StringBuffer(); //經過追加的方法,將每一個屬性拼接到此字符串中 //最外邊的public定義 sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n"); //裏邊的每個屬性 for(Field field:fs){ sb.append("\t");//空格 sb.append(Modifier.toString(field.getModifiers())+" ");//得到屬性的修飾符,例如public,static等等 sb.append(field.getType().getSimpleName() + " ");//屬性的類型的名字 sb.append(field.getName()+";\n");//屬性的名字+回車 } sb.append("}"); System.out.println(sb);
b,獲取特定的屬性,對比着傳統的方法來學習:
public static void main(String[] args) throws Exception{ /* User u = new User(); u.age = 12; //set System.out.println(u.age); //get */ //獲取類 Class c = Class.forName("User"); //獲取id屬性 Field idF = c.getDeclaredField("id"); //實例化這個類賦給o Object o = c.newInstance(); //打破封裝 idF.setAccessible(true); //使用反射機制能夠打破封裝性,致使了java對象的屬性不安全。 //給o對象的id屬性賦值"110" idF.set(o, "110"); //set //get System.out.println(idF.get(o)); }
4,獲取方法,和構造方法,再也不詳細描述,只來看一下關鍵字:
getDeclaredMethods() | 獲取全部的方法 |
getReturnType() | 得到方法的返回類型 |
getParameterTypes() | 得到方法的傳入參數類型 |
getDeclaredMethod("方法名",參數類型.class,……) | 得到特定的方法 |
getDeclaredConstructors() | 獲取全部的構造方法 |
getDeclaredConstructor(參數類型.class,……) | 獲取特定的構造方法 |
getSuperclass() | 獲取某類的父類 |
getInterfaces() | 獲取某類實現的接口 |
這樣咱們就能夠得到類的各類內容,進行了反編譯。對於JAVA這種先編譯再運行的語言來講,反射機制可使代碼更加靈活,更加容易實現面向對象。
五,反射加配置文件,使咱們的程序更加靈活:
assembly.load("當前程序集的名稱").CreateInstance("當前命名空間名稱".要實例化的類名);
這樣的好處是很容易的方便咱們變換數據庫,例如咱們將系統的數據庫從SQL Server升級到Oracle,那麼咱們寫兩份D層,在配置文件的內容改一下,或者加條件選擇一下便可,帶來了很大的方便。
固然了,JAVA中其實也是同樣,只不過這裏的配置文件爲.properties,稱做屬性文件。經過反射讀取裏邊的內容。這樣代碼是固定的,可是配置文件的內容咱們能夠改,這樣使咱們的代碼靈活了不少!
綜上爲,JAVA反射的再次學習,靈活的運用它,可以使咱們的代碼更加靈活,可是它也有它的缺點,就是運用它會使咱們的軟件的性能下降,複雜度增長,因此還要咱們慎重的使用它。
下面是引用的一篇文章:
Java反射在咱們Java學習的過程當中是很是重要的知識點。可能有些同窗認爲這個學習起來不容易理解,其實就我我的而言仍是比較簡單,學習起來也比較容易理解。下面我給你們總結一下Java反射學習的要點,同時給出幾個比較好的例子。
一、Java反射的概念
反射含義:能夠獲取正在運行的Java對象。
二、Java反射的功能
1)能夠判斷運行時對象所屬的類
2)能夠判斷運行時對象所具備的成員變量和方法
3)經過反射甚至能夠調用到private的方法
4)生成動態代理
三、實現Java反射的類
1)Class:它表示正在運行的Java應用程序中的類和接口
2)Field:提供有關類或接口的屬性信息,以及對它的動態訪問權限
3)Constructor:提供關於類的單個構造方法的信息以及對它的訪問權限
4)Method:提供關於類或接口中某個方法信息
注意:Class類是Java反射中最重要的一個功能類,全部獲取對象的信息(包括:方法/屬性/構造方法/訪問權限)都須要它來實現
四、編寫Java反射程序的步驟:
1)必須首先獲取一個類的Class對象
例如:
Class c1 = Test.class;
Class c2 = Class.forName(「com.reflection.Test」);
Class c3 = new Test().getClass();
2)而後分別調用Class對象中的方法來獲取一個類的屬性/方法/構造方法的結構
注意:若是要可以正常的獲取類中方法/屬性/構造方法應該重點掌握以下的反射類
Field
Constructor
Method
示例:此程序例子告訴你們如何操做Class/Field/Constructor/Method等與Java反射相關的類
package com.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class TestReflection { private String username; private String password; private int[] age; public TestReflection(String username, String password, int[] age) { super(); this.username = username; this.password = password; this.age = age; } public TestReflection() { username = "李白"; password = "123"; age = new int[]{10,11,12}; } public void setUserName(String username) { this.username = username; } private void setPassWord(String password) { this.password = password; } public static void test01() throws ClassNotFoundException { //使用三種方法均可以經過反射來獲取類對象Class Class c1 = TestReflection.class; Class c2 = Class.forName("com.reflection.TestReflection"); Class c3 = new TestReflection().getClass(); // 獲取指定的包名 String package01 = c1.getPackage().getName(); String package02 = c2.getPackage().getName(); String package03 = c3.getPackage().getName(); System.out.println("package01 = " + package01); System.out.println("package02 = " + package02); System.out.println("package03 = " + package03); // 獲取類的修飾符 int mod = c1.getModifiers(); String modifier = Modifier.toString(mod); System.out.println("modifier = " + modifier); // 獲取指定類的徹底限定名 String className = c1.getName(); System.out.println("className = " + className); // 獲取指定類的父類 Class superClazz = c1.getSuperclass(); String superClazzName = superClazz.getName(); System.out.println("superClazzName = " + superClazzName); // 獲取實現的接口 Class[] interfaces = c1.getInterfaces(); for (Class t : interfaces) { System.out.println("interfacesName = " + t.getName()); } // 獲取指定類的成員變量 Field[] fields = c1.getDeclaredFields(); for (Field field : fields) { modifier = Modifier.toString(field.getModifiers()); // 獲取每一個字段的訪問修飾符 Class type = field.getType(); // 獲取字段的數據類型所對應的Class對象 String name = field.getName(); // 獲取字段名 if (type.isArray()) { // 若是是數組類型則須要特別處理 Class tt = type.getComponentType(); //getComponentType()方法返回一個Class對象,表示數組的成員類型。若是該類不表示數組類,方法返回null.而後經過getName方法獲取數組元素類型 String arrType = type.getComponentType().getName() + "[]";//arrType 爲 int[] System.out.println("" + modifier + " " + arrType + " " + name + ";"); } else { System.out.println("" + modifier + " " + type + " " + name + ";"); } } // 獲取類的構造方法 Constructor[] constructors = c1.getDeclaredConstructors(); for (Constructor constructor : constructors) { String name = constructor.getName(); // 構造方法名 modifier = Modifier.toString(constructor.getModifiers()); // 獲取訪問修飾符 System.out.println("" + modifier + " " + name + "("); Class[] paramTypes = constructor.getParameterTypes(); // 獲取構造方法中的參數 for (int i = 0; i < paramTypes.length; i++) { if (i > 0) { System.out.print(","); } if (paramTypes[i].isArray()) { System.out.println(paramTypes[i].getComponentType().getName() + "[]"); } else { System.out.print(paramTypes[i].getName()); } } System.out.println(");"); } // 獲取成員方法 Method[] methods = c1.getDeclaredMethods(); for (Method method : methods) { modifier = Modifier.toString(method.getModifiers()); Class returnType = method.getReturnType(); // 獲取方法的返回類型 if (returnType.isArray()) { String arrType = returnType.getComponentType().getName() + "[]"; System.out.print("" + modifier + " " + arrType + " " + method.getName() + "("); } else { System.out.print("" + modifier + " " + returnType.getName() + " " + method.getName() + "("); } Class[] paramTypes = method.getParameterTypes(); for (int i = 0; i < paramTypes.length; i++) { if (i > 0) { System.out.print(","); } if (paramTypes[i].isArray()) { System.out.println(paramTypes[i].getComponentType() .getName() + "[]"); } else { System.out.print(paramTypes[i].getName()); } } System.out.println(");"); } } public static void test02() throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { // 反射調用方法,能夠經過Method類的invoke方法實現動態方法的調用 // public Object invoke(Object obj, Object... args) //該方法中有多個參數:method.invoke(o, new Object[] {參數1,參數2...}); // 第一個參數表明對象 // 第二個參數表明執行方法上的參數 // 若反射要調用類的某個私有方法,能夠在這個私有方法對應的Mehtod對象上先調用setAccessible(true) Class c1 = TestReflection.class; TestReflection t1 = (TestReflection) c1.newInstance(); // 利用反射調用無參的構造方法來建立類的對象 System.out.println("username == " + t1.username); System.out.println("password == " + t1.password); //得到名稱setUserName的方法public void com.reflection.TestReflection.setUserName(java.lang.String),參數爲String類型 Method method = c1.getDeclaredMethod("setUserName", String.class); method.invoke(t1, "Java反射的學習");//傳入參數爲字符串("Java反射的學習"),來調用類中的setUserName方法,此時已經改變實例t1的username的屬性值 System.out.println("username == " + t1.username); //調用私有方法private void com.reflection.TestReflection.setPassWord(java.lang.String),參數爲String類型 method = c1.getDeclaredMethod("setPassWord", String.class); //設置對私有方法的可操做權限 method.setAccessible(true); method.invoke(t1, "反射執行某個Private修飾的方法"); System.out.println("password == " + t1.password); } public static void main(String[] args) throws ClassNotFoundException, SecurityException, IllegalArgumentException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { // test01(); test02(); } } class Sum{ public static void main(String[] args) { int vec[] = new int[]{1, 5, 3}; // 第一種方法 int vec1[] = {37,47,23} ; // 第二種方法 int vec2[] = new int [3];//指定數組的元素個數 for(int i=0;i<3;i++){ vec[i]=i+1; //第三種方法 } } }
再給與個實例:
package org.cqut.java.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class CopyObject { public Object copyObject(Object object) throws Exception { // 1.獲取待操做類的一個Class對象 Class<?> classType = object.getClass(); // 2.獲取待操做類的一個實例 Constructor<?> constructor = classType .getConstructor(new Class<?>[] {}); Object copyObj = constructor.newInstance(new Object[] {}); // 3.獲取被拷貝類的成員變量 Field[] fields = classType.getDeclaredFields(); for (Field field : fields) { // 4.遍歷數組獲取各個成員變量名字 String name = field.getName();// 獲取成員變量名字; // 5.操做字符串獲取成員變量的set和get方法名字; String firstLetter = name.substring(0, 1).toUpperCase(); String getMethodName = "get" + firstLetter + name.substring(1); String setMethodName = "set" + firstLetter + name.substring(1); Method getMethod = classType.getMethod(getMethodName, new Class<?>[] {}); Method seMethod = classType.getMethod(setMethodName, new Class<?>[] { field.getType() }); /*最開始認爲如下兩個invoke方法的第一和參數都應該調用copyObj, * 可是最終的結果爲輸出爲默認的空值。 * copyObj:程序前面經過Constructor類的newInstance方法 * 獲取待操做類的一個實例; //Object value = getMethod.invoke(copyObj, new Object[] {}); //seMethod.invoke(copyObj, new Object[] { value }); /*如今改用以下方式了,輸出就正常了 * 因此產生疑惑:爲何第一個方法調用的object對象而不是copyObj呢? * */ Object value = getMethod.invoke(object, new Object[] {}); seMethod.invoke(copyObj, new Object[] { value }); } return copyObj; } public static void main(String[] args) throws Exception { Student student = new Student("Tom", 21); student.setId(111030805); CopyObject copy = new CopyObject(); Student student2 = (Student) copy.copyObject(student); System.out.println(student2.getId() + " " + student2.getName() + " " + student2.getAge()); } } // 一個被反射的JavaBean class Student { private long id; private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } 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; } public long getId() { return id; } public void setId(long id) { this.id = id; } }
對於利用object給copyObj賦值的invoke的解惑:
Object value = getMethod.invoke(object, new Object[] {}); seMethod.invoke(copyObj, new Object[] { value }); 這兩句代碼的做用以下, 第一句,獲取object中的值。 第二句,將該值設置到copyObj中。 這樣才能完成賦值。 若是按你所說 //Object value = getMethod.invoke(copyObj, new Object[] {}); //seMethod.invoke(copyObj, new Object[] { value }); 那就是講從copyObj獲取的值,賦值給copyObj,這樣作根本毫無心義。 for (Field field : fields) { String name = field.getName(); field.setAccessible(true); Object value = field.get(object); field.set(copyObj, value); } for循環裏這樣寫,就成功的將object中的值賦值到了copyObj中。