黑馬程序員-反射機制

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

問題1: Class類是什麼?有什麼作用?

Class類是所有類的基類,是每一個類放在內存中的字節碼。
通過Class類可以知道,每一個類中的所有組成部分。包括類中屬性,該類的構造函數,該類所擁有的方法等內容。

問題2:如何獲得一個類的Class類的字節碼實例對象,三種方法(以Person類爲例):

1)Class cls1 = Person.class
2)Class cls2 = person.getClass()
3)Class cls3 = Class.forName(“java.lang.String”)
forName加載有兩種,一種是已經存在了,直接加載,另一種是不存在,先加載到虛擬機中在應用。

問題3:Class類有幾種基本字節碼?

基本字節碼共九種,包括8種基本數據類型和Void.class,是否是基本自己碼可以用isPrimitive()來判斷。用isArray()判斷是否是數組。

具體看下面代碼實例:

class ReflectTest
{
    public static void main(String args[])
    {
        String str = "abc";
        Class cls1 = String.class;
        Class cls2 = str.getClass();
        Class cls3 = Class.forName("java.lang.String");
        System.out.println("cls1==cls2");//true
        System.out.println("cls1==cls2");//true

        System.out.println("cls1.isPrimitive()");//false
        System.out.println("int.class.isPrimitive()");//true
        System.out.println("int.class==Integer.class");//false
        System.out.println("int.class==Integer.Type");//true
        System.out.println("int[].class.isPrimitive()");//false
        System.out.println("int[].class.isArray()");//true
    }
}

(一)利用反射得到構造方法,並實例化對象

1)正常情況:String str = new String(new StringBuffer(“abc”));
2)利用反射:Constructor con=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
String str = con.newInstance(new StringBuffer(“abc”));
3)String.class類中有一個方法newInstance()是獲得無參構造。

示例1如下:
首先定義已知類:ReflectPoint

class ReflectPoint
{
    private int x;//私有屬性
    public int y;//公共屬性
    public RefletctPoint(int x,int y)//含有兩個整型參數的構造方法
    {
        super();
        this.x = x;
        this.y = y;
    }
}

1)獲取公共屬性y

ReflectPoint rp = new ReflectPoint(3,5);//獲得該類的實例對象
Field fiedlY = rp.getClass().getField("y");//通過該類的實例對象獲得該類的公共屬性y
System.out.println(fieldY.get(rp));//取得該類對應的此實例對象的公共屬性y對應的值,結果爲5。

2)私有屬性獲得方式

Field fieldX = rp.getClass().getDeclaredField("x");//通過該類的實例對象獲得該類的私有屬性x
fieldX.setAccessible(true);//設置該私有屬性可以被訪問。
System.out.println(fieldX.get(rp));//取得該類對應的此實例對象的私有屬性x對應的值,結果爲3。

示例2:
利用反射:將任意一個對象中的所有String 類型的成員變量所對應的字符內容中的‘b’改爲 ‘a’。
首先定義已知類

class ReflectPoint
{
    public String str1 = "ball";
    public String str2 = "basketball";
    public String str3 = "all";
    public String toString()
    {
        return str1+"......"+str2+"......"+str3+"......";
    }
}

封裝一個函數進行改寫操作

public static void changeStringValue(Object obj) throws Exception
{
    Field[] fields = obj.getClass().getFields();
    for(Field field:fields)
    {
        if(field.getType()==String.class)
        {
            String oldValue = (String)field.get(obj);
            String newValue = oldValue.replace('b','a');
            field.set(obj,newValue);
        }
    }
}

在主函數中調用並驗證

{
    ReflectPoint rp = new ReflectPoint();
    changeStringValue(rp);
    System.out.println(rp);
}

運行結果如下:
這裏寫圖片描述
改寫成功!

(三)利用反射:調用方法

以java.lang.String類爲例,獲取它的CharAt()方法

String str = "abc";
Method methodCharAt = String.class.getMethod("charAt",int.class);
System.out.println(methodCharAt.invoke(str1,1));//結果爲b

此處invoke()爲調用的意思,其中第一個參數爲調用的對象,第二個爲該方法的參數。如果是靜態函數,則第一個參數爲null,應書寫如下:

System.out.println(methodCharAt.invoke(null,1));

示例3: 用反射提供一個程序,根據用戶提供的類名,調用該類的main方法

首先寫出已知類ReflectTest:

package com.test;
public class ReflectTest
{
    public static void main(String args[])
    {
        for(String arg:args)
        {
            System.out.println(arg);
        }
    }
}

在另一個程序中調用:

public class ReflectDemo
{
    public static void main(String args[])
    {
        String startingClassName = args[0];
        Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);
        mainMethod.invoke(null,(Object)new String[]{"123","345","234"});
        mainMethod.invoke(null,new Object[]{new String[]{"123","345","234"}});
    }
}

程序運行結果如下:
[“123”,”345”,”234”]
“123”
“345”
“234”

此處invoke()方法的第二參數,作爲被調用方法的參數傳入,其形式爲Object數組形成,也可以爲Object對象。

附帶:分析一下數組與Object類的關係

看如下示例4:

public class ArrayObjectDemo
{
    public static void main(String args[])
    {
        int[] a1 = new int[3];
        int[] a2 = new int[4];
        int[][] a3 = new int[2][3];
        String[] a4 = new String[3];
        System.out.println(a1.getClass()==a2.getClass());//true
        System.out.println(a1.getClass()==a3.getClass());//false
        System.out.println(a1.getClass()==a4.getClass());//false
        System.out.println(a1.getClass.getName());//I
        System.out.println(a1.getClass.getSuperclass().getName());//
        System.out.println(a4.getClass.getSuperclass().getName());

        Object obj1 = a1;
        Object obj2 = a4;
        Object[] obj3 = a3;
        Object[] obj4 = a4;
        Object[] obj5 = a1;//此處編譯不通過。
        System.out.println(a1);//
        System.out.println(a4);//
        System.out.println(Arrays.asList(a1));//
        System.out.println(Arrays.asList(a4));//
    }
}

備註:Arrays.asList()這個方法的作用是把數組轉化爲List集合。

綜上例子可以發現:

1)具有相同維數和元素類型的數組屬於同一個類型,即具有相同的Class實例對象。
2)基本類型的一維數組可以被當作Object類型使用,不能當作Object[]類型使用。
3)非基本數據類型的一維數組既可以被當作Object類使用,也可以當作Object[]類型使用

利用反射機制和Array工具類完成對數組的操作:
示例5:打印數組。

封裝打印數組的方法如下:

public void printObj(Object obj)
{
    Class cla = obj.getClass();
    if(cla.isArray())
    {
        int len = Array.getLength(obj);
        for(int i=0;i<len;i++)
        {
            System.out.println(Array.get(obj,i));
        }
    }else
    {
        System.out.println(obj);
    }
}

主方法調用並獲得結果如下:

String[] a4 = new String[]{"a","b","c"};
printObj(a4);//結果爲a,b,c
printObj("abdc");//結果爲abcd

綜上是說明Class類的基本作用;
作爲反射機制,最大的作用在於:

實現框架功能

在許多框架中,在寫框架時,還不知道要被調用的類名,所以,在程序中無法直接new某個類的實例對象,而要用反射方式來做。
用例子說明如下:
示例6:新建一個Properties類,新建config.properties文件。

className=java.util.HashSet

該主方法(模擬爲框架代碼)

public class ReflectTest3
{
    public static void main(String args[])
    {
        InputStream is = new FileInputStream("config.properties");
        Properties props = new Properties();
        props.load(is);
        is.close();

        String className = props.getProperties("className");
        Collection collections = Class.forName(className);

        ReflectPoint pt1 = new ReflectPoint(3,3);
        ReflectPoint pt2 = new ReflectPoint(5,5);
        ReflectPoint pt3 = new ReflectPoint(3,3);

        collections.add(pt1);
        collections.add(pt2);
        collections.add(pt3);
        collections.add(pt1);

        System.out.println(collections.size());  //打印結果爲2
    }
}

定義被框架調用的類

class ReflectPoint
{
    public String str1 = "ball";
    public String str2 = "basketball";
    public String str3 = "all";
    public String toString()
    {
        return str1+"......"+str2+"......"+str3+"......";
    }
}

以上內容是對反射內容的全部概括,但是也是最基本的內容,多做練習,加深理解。

發佈了32 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章