(黑馬程式員—日記7)反射與內省——更上一層樓

來源:互聯網
上載者:User

------- 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進行內省操作。

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.