黑馬程序員_12_高新技術之反射

                                    黑馬程序員——反射

                                          ------- android培訓java培訓、期待與您交流! ----------

反射的概念:一個類是由多個部分組成,例如:成員變量,方法,構造函數等,反射就是加載類<把硬盤中的class文件加載到內存中>,並解剖類的各個組成部分,包括私有的。

應用場景:主要是用於製作框架的時候使用,通過配置文件進行反射。

那麼該如何加載類,如何反射呢?

Java是面嚮對象語言,萬物皆對象,所以sun公司把所有類用一個Class類來描述。

通過字節碼對象獲取構造方法,創建對象,使用了Constructor類描述一個類的構造方法。創建對象用newInstance
通過一個字節碼對象獲取到成員函數,sun使用了一個Method類描述函數。執行指定方法用invoke
通過字節碼對象獲取成員變量 , sun使用了Field描述了一個類的成員變量。

首先我們先描述一個Person類,以Person類爲列進行反射:
package cn.chen.reflect;

import java.io.InputStream;
import java.util.List;

public class Person {
	//成員變量
	public String name="aaa";
	private int age = 22;
	//構造函數
	public Person(){
		System.out.println("person");
	}
	public Person(String name){
		System.out.println(name);
	}
	public Person(String name,int pass){
		System.out.println(name+":"+pass);
	}
	//集合作爲形參傳遞
	private Person(List list){
		System.out.println("list");
	}
	public void aa1(){
		System.out.println("aa1...");
	}
	public void aa1(String name,int pass){
		System.out.println(name+":"+pass);
	}
	//返回類型是數組
	public Class[] aa1(String name,int[] pass){
		return new Class[]{String.class};
	}
	private void aa1(InputStream io){
		System.out.println(io);
	}
	//靜態方法
	public static void aa1(String name){
		System.out.println(name);
	}
	public static void main(String[] args) {
		System.out.println("main...");
	}
}

步驟如下:
1:首先把硬盤中的class文件加載進內存中;

加載類進內存有三種方法:
a:通過Class類中forName方法:forName(String  className)
b:通過上帝Object類中getClass方法:對象.getClass()
c:通過類名.class

代碼實現如下:
</pre><pre name="code" class="java">package cn.chen.reflect;

public class Demo1 {
	public static void main(String[] args) throws ClassNotFoundException {
		//第一種方法
		Class clazz1 = Class.forName("cn.chen.reflect.Person");
		//第二種方法
		Class clazz2 = new Person().getClass();
		//第三種方法
		Class clazz3 = Person.class;
	}
}


2:通過上個步驟獲得該類字節碼;通過該類的字節碼獲得該類的所以構造函數描述的類,該類有一個方法,根據構造函數指定的參數創建對象。

反射構造函數代碼如下:

package cn.chen.reflect;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class Demo2 {
	@Test
	public void test1() throws Exception{
		Class clazz = Class.forName("cn.chen.reflect.Person");
		Constructor c = clazz.getConstructor(null);
		Person p = (Person) c.newInstance(null);
		System.out.println(p.name);
	}
	@Test
	public void test2() throws Exception{
		Class clazz = Class.forName("cn.chen.reflect.Person");
		Constructor c = clazz.getConstructor(String.class);
		Person p = (Person) c.newInstance("chenlong");
		System.out.println(p.name);
	}
	@Test
	public void test3() throws Exception{
		Class clazz = Class.forName("cn.chen.reflect.Person");
		Constructor c = clazz.getConstructor(String.class,int.class);
		Person p = (Person) c.newInstance("xieli",20);
		System.out.println(p.name);
	}
	@Test
	public void test4() throws Exception{
		//獲得字節碼文件對象
		Class clazz = Class.forName("cn.chen.reflect.Person");
		//反射私有成員時用的方法
		Constructor c = clazz.getDeclaredConstructor(List.class);
		//暴力反射
		c.setAccessible(true);
		//返回類型是Object,所以需要強制轉換
		Person p = (Person) c.newInstance(new ArrayList());
		System.out.println(p.name);
	}
	@Test
	public void test5() throws Exception{
		Class clazz = Class.forName("cn.chen.reflect.Person");
		Person p = (Person) clazz.newInstance();
		System.out.println(p.name);
	}
}

舉一反三反射成員函數:

package cn.chen.reflect;

import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;

import org.junit.Test;

public class Demo3 {
	@Test
	public void test1() throws Exception{
		Person p = new Person();
		Class clazz = Class.forName("cn.chen.reflect.Person");
		Method method = clazz.getMethod("aa1", null);
		method.invoke(p,null);
		
	}
	@Test
	public void test2() throws Exception{
		Person p = new Person();
		//獲得字節碼文件對象
		Class clazz = Class.forName("cn.chen.reflect.Person");
		//獲得該類方法對象
		Method method = clazz.getMethod("aa1", String.class,int.class);
		//根據指定的參數,執行指定的方法。第一個參數是指定那個類的對象,後面參數是該類方法的形參
		method.invoke(p, "chen",25);
	}
	@Test
	public void test3() throws Exception{
		Person p = new Person();
		Class clazz = Class.forName("cn.chen.reflect.Person");
		Method method = clazz.getMethod("aa1", String.class , int[].class);
		Class cs[] = (Class[]) method.invoke(p, "xieli",new int[]{12,2});
		System.out.println(cs[0]);
		
	}
	@Test
	public void test4() throws Exception{
		Person p = new Person();
		Class clazz = Class.forName("cn.chen.reflect.Person");
		Method method = clazz.getDeclaredMethod("aa1", InputStream.class);
		method.setAccessible(true);
		method.invoke(p,new FileInputStream("H:\\1.jpg"));
	}
	@Test
	public void test5() throws Exception{
		
		Class clazz = Class.forName("cn.chen.reflect.Person");
		Method method = clazz.getMethod("aa1", String.class);
		//反射靜態方法,不需要對象、
		method.invoke(null,"chen");
	}
	@Test
	public void test6() throws Exception{
		Person p = new Person();
		Class clazz = Class.forName("cn.chen.reflect.Person");
		Method method = clazz.getMethod("main", String[].class);
		//第一種解決方案,由於傳入數組jvm會拆開,所以進行包裝
//		method.invoke(null,(Object)new String[]{"s"});
		//第二種解決方案。
		method.invoke(null,new Object[]{new String[]{"bb","aa"}});
	}
}

反射字段即成員變量

package cn.chen.reflect;

import java.lang.reflect.Field;

import org.junit.Test;

public class Demo4 {
	@Test
	public void test1() throws Exception{
		Person p = new Person();
		Class clazz = Class.forName("cn.chen.reflect.Person");
		//根據參數獲取對應的字段
		Field f = clazz.getField("name");
		System.out.println(f.get(p));
	}
	@Test
	public void test2() throws Exception{
		Person p = new Person();
		Class clazz = Class.forName("cn.chen.reflect.Person");
		Field f = clazz.getDeclaredField("age");
		f.setAccessible(true);
		System.out.println(f.get(p));
	}
}


注意部分:反射時如果是私有成員,必須使用帶有Declared字母的方法,如果需要使用時,需要調用setAccessible(true) 方法告訴Jvm需要暴力訪問。




------- android培訓java培訓、期待與您交流! ----------





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