java反射基本理論和實例

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中。
相關文章
相關標籤/搜索