------- android培訓、java培訓、期待與您交流! ----------
終於,似乎要脫離最最懵懂的階段了。學習了張老師的視頻之後,發現java還有這些高深的知識,比如反射,內省,用物件導向的眼光去看待硬碟裡的class檔案,原來他們也是對象,也可以被描述,java好強大啊。好好學習,更上一層樓吧。
反射
Class類
Class類代表Java類,它的各個執行個體對象對應各個類在記憶體中的位元組碼,例如,Person類的位元組碼,ArrayList類的位元組碼,等等。
一個類被類載入器載入到記憶體中,佔用一片儲存空間,這個空間裡面的內容就是類的位元組碼,不同的類的位元組碼是不同的,所以它們在記憶體中的內容是不同的,這一個個的空間可分別用一個個的對象來表示,這些對象顯然具有相同的類型,這個類型是什麼呢?
在反射中有三種方法得到各個位元組碼對應的執行個體對象(Class類型)
1.類名.class,例如,System.class //需要類已經載入進記憶體
2.對象.getClass(),例如,new Date().getClass() //需要有類的執行個體對象
3.Class.forName("類名"),例如,Class.forName("java.util.Date"); //比較常用的方法,相當於做了兩件事,把類載入進記憶體,再得到位元組碼
表示java類的Class類顯然要提供一系列的方法,來獲得其中的變數,方法,構造方法,修飾符,包等資訊,這些資訊就是用相應類的執行個體對象來表示,它們是Field、Method、Contructor、Package等等。
反射:反射就是把Java類中的各種成分映射成相應的java類。 //高人前輩的話,總結的比較好
Constructor類:
Constructor類代表某個類中的一個構造方法
得到某個類所有的構造方法:
例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();
得到某一個構造方法:
例子:Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class); //獲得方法時要用到類型
建立執行個體對象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc")); //調用獲得的方法時要用到上面相同類型的執行個體對象
Class.newInstance()方法:
例子:String obj = (String)Class.forName("java.lang.String").newInstance();
該方法內部先得到預設的構造方法,然後用該構造方法建立執行個體對象,不是常規的方法,因為很多類裡面沒有空參的構造方法,所以最好還是先得到一個類的構造方法,再根據構造方法裡的newInstance()來建立執行個體對象。
Field類:
Field類代表某個類中的一個成員變數
根據某個執行個體對象得到某個類中的一個欄位
Field field = obj.getClass().getField("x");//x為欄位名稱,
若欄位x是私人的,則用以下方法得到欄位
Field field = obj.getClass().getDeclaredField("x");
field.setAccessible(true);
field.get(obj);//用來得到某個對象上x欄位的值
改變一個類的執行個體對象中某個成員變數的值
class A{
...
String str = "abc";
...
}
class B
{
A obj = new A();
Field field = obj.getClass().getField("str"); //根據欄位名稱得到成員變數
String oldValue = (String)field.get(obj); //獲得成員變數的值
String new Value = oldValue.replace('b','a');
field.set(obj,newValue); //必須要用新的值替換某個對象上的成員變數的值
}
Method類:
Method類代表某個類中的一個成員方法
得到類中的某一個方法:
例子:
Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
調用方法:
通常方式:System.out.println(str.charAt(1));
反射方式: System.out.println(charAt.invoke(str, 1)); //通過Method類中的invoke方法來調用反射出來的方法
註:如果傳遞給Method對象的invoke()方法的第一個參數為null,說明該Method對象對應的是一個靜態方法
用反射方式執行某個類中的main方法:
mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"}); ,
註:編譯器會作特殊處理,編譯時間不把參數當作數組看待,也就不會數組打散成若干個參數了
數組的反射:
1、具有相同維數和元素類型的數組屬於同一個類型,即具有相同的Class執行個體對象。
範例程式碼:
int[] a1 = new int[2];
int[] a2 = new int[4];
a1.getClass()==a2.getClass();//true
2、代表數組的Class執行個體對象的getSuperClass()方法返回的父類為Object類對應的Class。
3、基本類型的一維數組可以被當作Object類型使用,不能當作Object[]類型使用;非基本類型的一維數組,既可以當做Object類型使用,又可以當做Object[]類型使用。
個人理解:可以把int[] 看成一個對象,
Object obj1 = a1;//可以
Object[] obj2 = a1;//不可以,可以理解成,把一個裝對象的容器和一個對象劃等號了
注意:列印Arrays.asList(a1);方法返回的結果,是一個雜湊碼。
內省(JavaBean)
JavaBean是一種特殊的Java類,主要用於傳遞資料資訊,這種java類中的方法主要用於訪問私人的欄位,且方法名符合某種命名規則。
可以理解為把有set和get方法的類看做是一個javaBean,因為要訪問私人欄位必須有set或get方法。
總之:一個類被當作javaBean使用時,JavaBean的屬性是根據方法名推斷出來的,它根本看不到java類內部的成員變數。
下面是一個簡單的javabean
class Person{
private String name;
private int age;
public void setName(String name){
this.name=name;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
對JavaBean的簡單內省操作
class A
{
private int x;
private int y;
...
set...
get...
...
}
class B
{
A obj = new A(); //建立需要進行內省操作的類的執行個體對象
String propertyName = "x"; //可以根據get和set方法推斷屬性名稱
PropertyDescriptor pd = new PropertyDescriptor(propertyName,obj.getClass()); //根據屬性名稱,得到屬性描述
Method methodGetX = pd.getReadMethod();//通過屬性描述對象上的方法反射出javaBean中的方法
Object retVal = methodGetX.invoke(obj);//調用方法
Method methodSetX = pd.getWriteMethod();
methodSetX.invoke(obj,3);
...
/*
以下是對JavaBean的複雜內省操作,先得到屬性描述的一個集合
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());//用內省類Introspector的靜態方法得到javaBean的資訊
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();//獲得javaBean上所有的屬性描述
for(PropertyDescriptor pd : pds) //遍曆判斷所需要的屬性描述,並操作
{
if(pd.getName().equals(propertyName))
{
Method methodGetX = pd.getReadMethod();
Object retVal = methodGetX.invoke(obj);
break ;
}
}
*/
}
BeanUtils工具包
使用BeanUtils工具包可以簡化對JavaBean的操作
首先要載入兩個JAR,commons-beanutils.jar和common-logging-1.1.jar
BeanUtils.setProperty(obj,"x","9");//這個字串的9傳給原來類中的x時,BeanUtils會自動進行類型轉換,轉成int型的9
javaBean中有一個屬性:private Date birthday;可進行如下操作
BeanUtils.setProperty(obj,"birthday.time","100");//Date類中有一個setTime()方法,這個BeanUtils可以進行屬性的毗連操作
BeanUtils裡的另一個設定屬性的操作
PropertyUtils.setProperty(obj,"x",9);//這個工具需要用x原來的類型進行設定,他不能進行類型的自動轉換
小總結: 反射學習來還是比較容易的,用我自己最簡單的話描述就是:通過反射得到類的位元組碼,並反射出類中的各種東西。內省的步驟就是先要得到屬性描述,然後才能對javaBean進行內省操作。