黑馬程序員_反射

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


一    反射的基石:Class類
1 Class類:描述java程序中的java類。例如:描述人這類事物用Person類。描述java中的類就用Class類。
(1)該類所描述的是類所屬的包,該類實現的接口,該類中定義的成員等等,都可以通過Class類得到。
(2)Class類的實例對象是字節碼文件對象。
(3)什麼是字節碼文件對象呢。當我們使用到某個類時,會從硬盤上將類編譯成class文件的字節碼,將字節碼加載進內存在創建出一個個的實例對象。
(4)那麼獲取字節碼實例對象有三種方式
第一種: Class cls1=類名.class
第一種: Class cls2=對象.getClass()
第一種: Class cls3=Class.forName(類的完整名字)

2 九個預定義的實例對象
基本數據類型boolean、byte、char、short、int、long、float、double和關鍵字 void 也表示爲 Class 對象。只要源代碼使用到對應的數據類型,內存就會產生對應的字節碼示例對象。
int.class==Integer_TYPE;
 
3 例子:

class  ClassDemo
{
	public static void main(String[] args) throws Exception
	{
		//創建String類對象
		String s="aaa";
		//獲取String類的字節碼
		Class cls1=String.class;
		Class cls2=s.getClass();
		Class cls3=Class.forName("java.lang.String");
		//判斷是否是同一個字節碼
		System.out.println(cls1==cls2);//結果爲true
		System.out.println(cls1==cls3);//結果爲true
		//判斷String類是不是原始類型
		System.out.println(cls1.isPrimitive());//結果爲false
		//判斷int類是不是原始類型
		System.out.println(int.class.isPrimitive());//結果爲true
	}
}



二    反射
1 概念:反射就是把java類中的各個成分映射成java類。
  例如:java類中有成員函數,成員方法,構造函數。通過Class類可以獲得這些信息。他們的類型分別是Field,Method,Constructor,他們也是java類。

2 Constructor類,用於描述類中的構造方法。可以通過Constructor類創建實例對象
(1)獲取構造方法的方式:
第一:Class類對象.getConstructors();//獲取某個類的全部構造方法,返回Constructor[]數組
第二:Class類對象.getConstructors(Class<?>... parameterTypes);//獲取某個類的一個構造方法,而具體是哪個要看構造方法對應的參數列表

3 通過獲取構造方法可以創建對應的實例對象
方法:Constructor的實例對象.newIntance(Object... initargs);//需要對返回類型進行強轉

4 例子:

import java.lang.reflect.*;
class ConstructorDemo 
{
	public static void main(String[] args) throws Exception
	{
		//獲取Person類的字節碼對象
		Class cls1=Person.class;
		//獲取Person類的全部構造方法
		Constructor[] cons=cls1.getConstructors();
		System.out.println(cons.length);//獲取構造方法數量
		//獲取Person中的某個構造方法
		Constructor con=cls1.getConstructor(String.class,int.class);
		//通過構造方法創建實例對象
		Person p1=(Person)con.newInstance("zhangsan",15);
		//用創建的實例對象調用方法
		System.out.println(p1.name+":"+p1.age);
	}
}

class Person
{
	String name;
	int age;
	public Person(){}
	public Person(String name)
	{
		this.name=name;
	}
	public Person(String name,int age)
	{
		this.name=name;
		this.age=age;
	}
}

5 Field類,用於描述類中的成員變量

(1)獲取類中的某個成員變量的Constructor對象用getField(String name),此方法不能獲取私有的變量
(2)獲取類中私有的變量的Constructor對象用getDeclaredField(String name);
(3)例子:

import java.lang.reflect.*;
class  FieldDemo
{
	public static void main(String[] args) throws Exception
	{
		//創建學生對象
		Student s=new Student("lisi",25);
		//獲取學生類字節碼對象
		Class cls1=s.getClass();
		//獲取學生類的某個成員變量
		Field fieldName=cls1.getField("name");
		//獲取某個學生對象的成員變量的值
		String s_name=(String)fieldName.get(s);
		System.out.println(s_name);

		//獲取學生類中的私有成員變量
		Field fieldAge=cls1.getDeclaredField("age");
		//將私有變量設置爲可訪問的
		fieldAge.setAccessible(true);
		//獲取s學生對象的age值
		int s_age=(int)fieldAge.get(s);
		System.out.println(s_age);
	}
}

class Student
{
	public String name;
	private int age;
	public Student(String name,int age)
	{
		this.name=name;
		this.age=age;
	}
}

(4) Field類反射練習:

//將一個java類中的String類型的成員變量中的值的字母改掉
/*
思想:
1 獲取類中所有的成員變量的Field對象數組
2 遍歷Field數組並判斷類型
3 如果是String類型的就獲取他的值並將對應的字母換成指定的字母
*/
import java.lang.reflect.*;
class FieldTest 
{
	public static void main(String[] args) throws Exception
	{
		//創建男人對象
		Man m=new Man();
		//獲取Man類的字節碼對象
		Class cls1=m.getClass();
		//獲取類中成員變量的Field數組
		Field[] fields=cls1.getFields();
		System.out.println(fields.length);
		//遍歷數組
		for(Field field:fields)
		{
			//判斷成員變量所屬的類型
			if (field.getType()==String.class)
			{
				//獲取變量的值
				String oldVal=(String)field.get(m);
				//將變量的值改掉
				String newVal=oldVal.replace('n','m');
				//將m對象變量上此 Field 對象表示的字段設置爲指定的新值
				field.set(m,newVal);
			}
		}
		System.out.println(m.toString());

	}
}
class Man
{
	public String name="nanren";
	public int age=20;
	public String id="work000";
	public String sex="man";
	public String toString()
	{
		return name+":"+id+":"+sex;
	}
}

6 Method類,用於描述類中的成員函數

(1)例子:

//用反射的方法調用Person類中的getName()方法
import java.lang.reflect.*;
class MethodDemo 
{
	public static void main(String[] args) throws Exception
	{
		//創建人對象
		Person p=new Person();
		//獲取Person字節碼對象
		Class cls1=p.getClass();
		//獲取Person類中的setName()方法Method對象
		Method method_setName=cls1.getMethod("setName",String.class);
		//調用setName()方法
		method_setName.invoke(p,"lisi");
		//獲取Person類中的getName()方法Method對象
		Method method_getName=cls1.getMethod("getName");
		//調用Method類的getName()方法
		String name=(String)method_getName.invoke(p);
		System.out.println(name);
	}
}

class Person
{
	private String name;
	public String getName()
	{
		return name;
	}
	public void setName(String name)
	{
		this.name=name;
	}
}

7 數組的反射
(1)具有相同維數和數據類型的數組具有相同的Class字節碼實例對象。
(2)基本數據類型的一位數據可以被當作Object使用,不可以被當作Object[]使用。引用數據類型的一維數組可以被當作Object使用也可以被當作Object[]使用。
(3)例子:

import java.lang.reflect.*;
class ArrayDemo 
{
	public static void main(String[] args) 
	{
		int[] arr1=new int[]{1,2,3};
		int[] arr2=new int[2];
		String[] arr3=new String[3];
		int[][] arr4=new int[2][3];
		//分別獲取數組的Class字節碼對象
		Class cls1=arr1.getClass();
		Class cls2=arr2.getClass();
		Class cls3=arr3.getClass();
		Class cls4=arr4.getClass();
		System.out.println(cls1==cls2);//true
		System.out.println(cls1==cls3);//flase
		System.out.println(cls1==cls4);//false	
		//結論:只有維數和數據類型一致,對應的字節碼對象是同一份

		//獲取父類
		System.out.println(cls1.getSuperclass().getName());//返回java.lang.Object
		System.out.println(cls3.getSuperclass().getName());//返回java.lang.Object

		//調用方法打印對象
		print(arr1);
		
	}
	//定義方法用反射打印對象
	public static void print(Object obj)
	{
		//獲取Object的字節碼對象
		Class cls=obj.getClass();
		//判斷是不是數組
		if(cls.isArray())
		{
			//遍歷數組並打印
			for(int x=0;x<Array.getLength(obj);x++)
			{
				System.out.println(Array.get(obj,x));
			}
		}
		else
			System.out.println(obj);
	}
}

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