1. 程式人生 > >JavaSE基礎學習筆記及案例(三)反射

JavaSE基礎學習筆記及案例(三)反射

1.反射

1.1反射概述
1.java反射機制是在執行狀態時,對於任意一個類,都可以知道這個類的所有屬性和方法;
動態獲取資訊以及動態呼叫物件的方法稱為java反射機制;
2.反射的三種方式
(1)Object類的getClass()方法,判斷兩個物件是否是同一個位元組碼檔案;
(2)靜態屬性class,鎖物件;
(3)Class類中靜態方法forName(),讀取配置檔案;

public class demo2_Ref {
	/**
	 * @param args
	 * 反射的三種獲取方式
	 * @throws ClassNotFoundException 
	 */
	public static void main(String[] args) throws ClassNotFoundException {
		Class clazz1 = Class.forName("day8.Fac_Method.Person");//1
		Class clazz2 = Person.class;//2
		
		Person p = new Person();
		Class clazz3 = p.getClass();//3
		
		System.out.println(clazz1==clazz2);
		System.out.println(clazz2==clazz3);
	}
}

1.2反射之Class.forName()讀取配置檔案
—newInstance為class建立一個例項物件

//反射實現
BufferedReader br = new BufferedReader(new FileReader("config.properties"));
Class clazz = Class.forName(br.readLine());
Fruit f = (Fruit) clazz.newInstance();//為class建立一個例項物件	

程式碼實現:
第一步:建立配置檔案config.properties;

day8.Fac_Method.Apple

第二步:

package day8.Fac_Method;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class demo3 {
	public static void main(String[] args) throws Exception{
		//反射實現
		BufferedReader br = new BufferedReader(new FileReader("config.properties"));
		Class clazz = Class.forName(br.readLine());
		Fruit f = (Fruit) clazz.newInstance();
		Juicer j = new Juicer();
		j.run(f);
	}
}
interface Fruit{
	public void squeeze();
}
class Apple implements Fruit{
	public void squeeze(){//榨汁方法
		System.out.println("榨蘋果汁"); 
	}
}
class Orange implements Fruit{
	public void squeeze(){
		System.out.println("榨橘子汁");
	}
}
//榨汁機
class Juicer{
	public void run(Fruit f){//榨汁機執行方法
		f.squeeze();
	}
}

1.3通過反射獲取構造方法
無參構造與有參構造獲取物件的方法
1.獲取位元組碼檔案

Class clazz = Class.forName("day8.Fac_Method.Person");

2.獲取有參構造

Constructor c = clazz.getConstructor(String.class,int.class);

3.通過有參構造建立物件

Person p = (Person) c.newInstance("張三",23);

4.列印輸出p;

Person [name=張三, age=23]

5.程式碼實現:

第一步:建立Person類

public class Person {

	private String name;
	private int age;
	/*public Person() {
		super();//註釋掉無參,在反射中就只能通過有參來實現
	}*/
	public Person(String name, int age) {
		super();
		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;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}

第二步:通過反射獲取物件(無參與有參)

/**
 * @author ZHENG
 *	通過反射獲取無參構造和獲取有參構造的區別
 */
public class demo4_Constrct {
	public static void main(String[] args) throws Exception {
	//1.獲取位元組碼檔案
		 Class clazz = Class.forName("day8.Fac_Method.Person");
		/*
			//2.通過無參構造獲取物件
			Person p = (Person) clazz.newInstance();
			System.out.println(p);
		*/
	//2.獲取有參構造
		Constructor c = clazz.getConstructor(String.class,int.class);
	//通過有參構造建立物件	
		Person p = (Person) c.newInstance("張三",23);
		System.out.println(p);
	}
} 

1.4通過反射獲取成員變數
1.獲取位元組碼檔案

Class clazz = Class.forName("day8.Fac_Method.Person");

2.獲取有參構造

Constructor c = clazz.getConstructor(String.class,int.class);

3.通過有參構造建立物件

Person p = (Person) c.newInstance("張三",23);

4.在Person類中成員變數為私有的,所以反射需要通過暴力來獲取私有欄位

Field f = clazz.getDeclaredField("name");

5.暴力獲取到欄位,需要去除私有許可權>>>>修改成員變數

f.setAccessible(true);//去除私有許可權
f.set(p, "李四");

6.輸出p的結結果為

Person [name=李四, age=23]

完整程式碼:

public class demo5_Filed {
	public static void main(String[] args) throws Exception{
		//1.獲取位元組碼檔案
		Class clazz = Class.forName("day8.Fac_Method.Person");
		//2.獲取有參構造
		Constructor c = clazz.getConstructor(String.class,int.class);
		//3.通過有參構造建立物件
		Person p = (Person) c.newInstance("張三",23);
		//4.獲取name欄位,即使私有也無關(暴力反射)
		/*
			Field f = clazz.getField("name");
			f.set(p, "李四");//修改獲取的成員變數
		*/		
		Field f = clazz.getDeclaredField("name");//暴力獲取私有的欄位
		f.setAccessible(true);//去除私有許可權
		f.set(p, "李四");//修改獲取的成員變數
		System.out.println(p);
	}
}

1.5通過反射獲取方法並且執行
1.根據1.3的Person類,完善Person類,添加了eat()方法【無參】

public void eat(){
		System.out.println("今天吃了頓霸王餐");
}//如果是私有的方法需要暴力獲取,本例不需要

2.獲取位元組碼檔案【Person】

Class clazz = Class.forName("day8.Fac_Method.Person");

3.獲取有參構造

Constructor c = clazz.getConstructor(String.class,int.class);

4.通過有參建立物件

Person p = (Person) c.newInstance("張三",23);

5.通過getMethod獲取Person類裡的方法

Method m = clazz.getMethod("eat");

6.執行獲取到的方法

m.invoke(p);

7.輸出結果

今天吃了頓霸王餐

完整程式碼:

/**
 *	無參執行方法
 */
public class demo6 {
	public static void main(String[] args) throws Exception{
		Class clazz = Class.forName("day8.Fac_Method.Person");
		Constructor c = clazz.getConstructor(String.class,int.class);
		Person p = (Person) c.newInstance("張三",23);
		//獲取eat方法
		Method m = clazz.getMethod("eat");
		//執行該方法
		m.invoke(p);
	}
}

1.根據1.3的Person類,完善Person類,添加了eat(int num)方法【有參】

public void eat(int num){
		System.out.println("今天吃了"+num+"頓霸王餐");
}//如果是私有的方法需要暴力獲取,本例不需要

2.獲取位元組碼檔案【Person】

Class clazz = Class.forName("day8.Fac_Method.Person");

3.獲取有參構造

Constructor c = clazz.getConstructor(String.class,int.class);

4.通過有參建立物件

Person p = (Person) c.newInstance("張三",23);

5.通過getMethod獲取Person類裡的方法

Method m = clazz.getMethod("eat", int.class);//引數為位元組碼檔案

6.執行獲取到的方法

m.invoke(p, 3);

7.輸出結果

今天吃了3頓霸王餐

1.6通過泛型擦除實現列表追加資料

public static void main(String[] args) throws Exception{
		ArrayList<Integer> list = new ArrayList<>();
		list.add(111);
		list.add(222);
		Class clazz = Class.forName("java.util.ArrayList");
		Method m = clazz.getMethod("add", Object.class);//add方法的引數為Object型別
		m.invoke(list, "abc");//執行
		System.out.println(list);
	}

結果

[111, 222, abc]

1.7反射練習
1定義一個Test_exec類;
2.寫一個Properties格式的配置檔案,配置類的完整名稱;
3.寫一個程式讀取這個配置檔案,獲得完整名稱並載入這個類,用反射執行run方法;

第一步:建立一個Test_exec類,裡面包括run方法;

package day9_fanshe;
public class Test_exec {
	public void run(){
		System.out.println("Welcome to Bj");
	}
}

第二步:建立配置檔案xxx.properties,內容為Test_exec的完整路徑

day9_fanshe.Test_exec

第三步:建立Test_demo類,通過反射執行run()方法

public class Test_demo {
	public static void main(String[] args) throws Exception{
		//1.建立流物件,讀取配置檔案
		BufferedReader br = new BufferedReader(new FileReader("xxx.properties"));
		//2.讀取類名,獲取位元組碼物件
		Class clazz = Class.forName(br.readLine());
		//3.通過位元組碼物件建立物件【無參】
		Test_exec tc = (Test_exec) clazz.newInstance();
		//4.呼叫方法
		tc.run();
	}
}

1.8反射之動態代理【很重要】
第一步:建立一個User介面;
通過UserImpl實現該介面

public interface User {
	public void add();
	
	public void delete();
}
public class UserImpl implements User {
	@Override
	public void add() {
		System.out.println("新增功能");
	}
	@Override
	public void delete() {
		System.out.println("刪除功能");
	}
}

第三步:建立MyInvocationHandler類實現InvocationHandler【實現代理】

/**
 * @author ZHENG
 *	動態代理
 */
public class MyInvocationHandler implements InvocationHandler {
	private Object target;
	
	public MyInvocationHandler(Object target) {
		super();
		this.target = target;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("許可權校驗");
		//執行被代理target的方法
		method.invoke(target, args);
		System.out.println("日誌記錄");
		return null;
	}
}

第四步:建立測試類,實現程式碼

public class Test {
	public static void main(String[] args){
		UserImpl ui = new UserImpl();
		ui.add();
		ui.delete();
		System.out.println("===================");
		 /*
		 	ui.getClass()獲取位元組碼檔案;
		  	Proxy.newProxyInstance:接收的三個引數>>>>
		 *  第一個引數:所有類載入器;
		 *  第二個引數:所有介面
		 *  第三個引數:MyInvocationHandler這個類的子類物件
	
			ui.getClass().getClassLoader()獲取類載入器
			ui.getClass().getInterfaces()獲取所有的介面
		*/
		MyInvocationHandler m = new MyInvocationHandler(ui);
		User u = (User) Proxy.newProxyInstance(ui.getClass().getClassLoader(), ui.getClass().getInterfaces(),m);
		u.add();
		u.delete();
	}
}

結果如下:

新增功能
刪除功能
===================
許可權校驗
新增功能
日誌記錄
許可權校驗
刪除功能
日誌記錄