使用類的反射機制來訪問類的私有成員變量

首先我們來看個實例吧,一般根據Java的語法,類的私有成員變量只能被內部的方法所訪問;但是通過類的反射機制,卻可以訪問這個類的所有變量(包括私有成員變量),

我們這個實例吧。

import java.lang.reflect.Field;



public class PrivateTest1 {

	/**
	 * @param args
	 */
	public static void main(String[] args)throws Exception {
		PrivateTestClass1 obj =new PrivateTestClass1("leonardo"); //獲取對象
		//獲取Class 對象
		Class clazz =obj.getClass();

		Field f =clazz.getDeclaredField("field"); //獲取類的field
		//設置 私有變量可以訪問的權限
		f.setAccessible(true);
		//打印field的值
		System.out.println(f.get(obj));

	}
	
}
class PrivateTestClass1{
	
	private String field;
	
	public PrivateTestClass1(String field){
		this.field =field;
	}
}
這裏的關鍵是將私有變量的訪問權限改爲true  否則類的反射也是無法訪問的。

接下來我這邊要做一個拓展;是這些天面試的時候,碰到一個面試題:

能否將ReadOnlyClass 類的一個對象,把它的name屬性的值由hello改爲world?如果能,請寫出實現代碼。如果不能請說明理由。
Public final class ReadOnlyClass (
           private String name = “hello”;
           public String getName() {
                       return name;
            }

}

 剛開始的時候 ,我竟然不加思考的回答不可以(由於該私有變量沒有set方法),可是回來仔細一想不對勁了;因爲類的反射是可以處理的。下面我們就用類的反射來解決這個問題。

import java.lang.reflect.Field;

/**
 * 類反射 訪問私有變量、修改私有變量
 * @author leo
 *
 */
public class PrivateTest {
	/**
	 * @param args
	 
	 */
	public static void main(String[] args) throws Exception {
		PrivateTestClass obj =new PrivateTestClass();
		
		Class clazz =obj.getClass(); //獲取obj對象的 class 
		
		Field f =clazz.getDeclaredField("name"); //獲取類的field
		//關鍵步驟
		f.setAccessible(true); //設置私有變量的可訪問性爲true
		System.err.println(f.get(obj));
		// ,可以同累的反射進行修改 木有set方法的 私有變量
		f.set(obj, "world");
		//打印出對象
		System.out.println(f.get(obj));
	}

}
final class PrivateTestClass{
	
	private String name ="hello";
	
	public String getName() {
		return name;
	}
}

編寫完成之後,我們進行編譯運行一下,發現打印出來的兩個 值:

hello
world

看見沒有,類的反射是可以處理該種情況,當然這種情況在我們框架中是很常見的。


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

實例2:利用反射將一個bean的對象的值  封裝到map中 

在寫service 層接口時,爲了讓每個接口方法的可用性更廣,我在項目中定義參數都是用一個Map<String,Object> 來定義;可是controller 傳遞過來的參數都是一個VO 的bean 對象,所以我爲了代碼可維護性更高,減少冗餘代碼,用反射寫了個工具類;

beanVO :

package com.zeng.map;

public class Student {
	
	private String name;
	
	private String age;
	
	private String sex;
	
	private String grade;
	
	private String className;
	
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public String getGrade() {
		return grade;
	}

	public void setGrade(String grade) {
		this.grade = grade;
	}

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}
	
	
}

工具類以及測試方法:

package com.zeng.map;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * 利用反射將一個bean 的對象的值封裝到Map中
 * @author leo-zeng
 *
 */
public class BeanUntils {
	
	public static <T> Map<String,Object> convertBeanToMap(T t) throws Exception{
		Map<String,Object> condition = new HashMap<String, Object>();
		//獲取類的實例
		Field[] fields = t.getClass().getDeclaredFields();
		for (Field field : fields) {
			//設置字段是可訪問的
			field.setAccessible(true);
			Object value  =field.get(t);
			if(value != null){
				if(value instanceof String){
					String _v = (String)value;
					if(_v != null && _v.trim().length()>0){
						condition.put(field.getName(), _v.trim());
					}
				}else{
					condition.put(field.getName(), value);
				}
			}
		}
		return condition;
	}
	
	public static void main(String[] args) {
		Student student = new Student();
		student.setName("leo");
		student.setAge("22");
		student.setGrade("3");
		try {
			Map<String,Object> condition =BeanUntils.convertBeanToMap(student);
			
			for (Map.Entry<String, Object> entry : condition.entrySet()) {
				System.out.println(entry.getKey()+":"+entry.getValue());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
得到的測試結果是

age:22
name:leo
grade:3







發佈了25 篇原創文章 · 獲贊 20 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章