------- 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);
}
}