黑馬程序員——反射
-------
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需要暴力訪問。