---------------------- ASP.Net+Android+IOS開發、.Net教育訓練、期待與您交流! ----------------------
1:什麼是反射:反射的概念主要指類可以通路、檢測和修改它本身狀态或行為的一種能力,它能讓java類自身進行檢查,并能直接操作類的内部屬性。
反射總結:就是把Java類中的所有成分反射成不同的java類
2:什麼是反射機制:Java反射機制是在運作狀态中,對于任意一個類,都能夠知道這個類中的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性;這種動态擷取的資訊以及動态調用對象的方法的功能稱為java語言的反射機制
反射的基石àClass類
1.所有的類檔案都有共同屬性,是以可以向上抽取,把這些共性内容封裝成一個類,這個類就叫Class(描述位元組碼檔案的對象)。
Class類中就包含屬性有field(字段)、method(方法)、construction(構造函數)。
而field中有修飾符、類型、變量名等複雜的描述内容,是以也可以将字段封裝稱為一個對象。用來擷取類中field的内容,這個對象的描述叫Field。同理方法和構造函數也被封裝成對象Method、Constructor。要想對一個類進行内容的擷取,必須要先擷取該位元組碼檔案的對象。該對象是Class類型。
Class類描述的資訊:類的名字,類的通路屬性,類所屬于的包名,字段名稱的清單,方法名稱的清單等。每一個位元組碼就是class的執行個體對象。如:classcls=Data.class;
什麼是位元組碼:
當源程式中用到類時,首先要從硬碟把這個類的那些二進制代碼,一個類編譯成class放在硬碟上以後,就是一些二進制代碼,要把這些二進制代碼加載到記憶體中裡面來,再用這些位元組碼去複制出一個一個對象來。
2.Class和class的差別
1)class:Java中的類用于描述一類事物的共性,該類事物有什麼屬性,沒有什麼屬性,至于這個屬性的值是什麼,則由此類的執行個體對象确定,不同的執行個體對象有不同的屬性值。
2)Class:指的是Java程式中的各個Java類是屬于同一類事物,都是Java程式的類,這些類稱為Class。例如人對應的是Person類,Java類對應的就是Class。Class是Java程式中各個Java類的總稱;它是反射的基石,通過Class類來使用反射。
反射的作用(重點):
可以通過反射機制取得對象的類型
取得對象的方法、屬性、構造器
可以建立對象并通路任意對象方法和屬性
反射兩個缺點:
性能問題。用于字段和方法介入時反射要遠慢與直接的代碼
使用反射會模糊程式内部實際要發生的事情,使程式對程式邏輯的可讀性變差
得到位元組碼對象的方式有三種
(1)在源程式裡直接寫上類的名字.class 例:Person.class
(2)在通過對象調用getClass(),傳回位元組碼 例:per.getClass()
(3)用Class類的靜态方法去查詢或加載位元組碼
例:Class.forName(“類名”)
PS:一般開發都用第三種,傳入字元串即可得到類的位元組碼
問:以下得到的三個位元組碼是不是同一份?
String str1 = "abc";
Class cls1 = str1.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");
System.out.println(cls1 == cls2);//輸出true
System.out.println(cls1 == cls3); //輸出true
面試提問:Class.forName(“類名”)的作用是什麼?
回答:
有兩個作用
1:如果該類的位元組碼曾經被加載過,那麼直接傳回該類的位元組碼:
2:如果該類還沒有被加載進記憶體,那麼此時就進行加載該類的位元組碼,緩存在記憶體中,并傳回位元組碼對象
回答:得到的都是同一份位元組碼
isprimitive():判斷一個類是不是一個基本類型的方法
isArray():判斷一個類是不是數組類型的方法
代碼:
String str1 = "abc";
Class cls1 = str1.getClass();
System.out.println(cls1.isPrimitive());//結果為false, 說明String不是基本類型
System.out.println(int.class.isPrimitive());//結果為true
System.out.println(int.class == Integer.class); //結果為true
System.out.println(int.class == Integer.TYPE); //結果為true
System.out.println(int[].class.isPrimitive());//結果為false
System.out.println(int[].class.isArray()); //結果為true
System.out.println(int.Class.isprimitive());//結果為true
總之,在源程式中出現的資料類型,都有各自對應的Class執行個體對象
九個預定義Class執行個體對象,即八個基本資料類型(boolean、byte、char、short、int、long、float和 double)和一個void類型的位元組碼對象。也就是說他們都有自己的Class對象,void的是void.class。
反射就是把Java類中的各個成分映射成相應的java類。而Class類提供了一系列的方法,來獲得其中的變量,方法,構造方法,修飾符,包等資訊。這些資訊就是用相應的類的執行個體對象來表示的,他們是Field(變量或字段),Method(方法),Contructor(構造器),Package(包)等等
擷取類中的方法
getDeclaredMethods():取得類中定義了的所有的方法清單
(包括private,public,protected、packed),但是不包括從父類中繼承來的方法
使用:位元組碼對象.getDeclaredMethods(),傳回值類型是Methods類型
getMethod(name,參數位元組碼):擷取類的所有公有方法,包括從父類中繼承來的方法,傳回Method類型(這點是與getDeclaredMethods()的差別)
name為想取得的方法的名字,後面的參數的自己碼為方法可能有多個重載形式,這裡通過參數的位元組碼來識别
例:調用String類型的charAt()
String str = “abc”;
Method methodCharAt = str.getClass.getMethod(“charAt”,int.class);
System.out.println(methodCharAt.invoke(str,1));//傳入要截取的字元串對象和要操作的下标
//輸出是“b” ps: invoke()表示調用
如果invoke()中傳入的對象是null,說明該方法對應的方法是靜态方法,靜态方法調用不需要對象
代碼示例:
Method methodCharAt = String.class.getMethod("charAt", int.class);
System.out.println(methodCharAt.invoke(str1, 1));
System.out.println(methodCharAt.invoke(str1, new Object[]{2}));
//TestArguments.main(new String[]{"111","222","333"});
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
//mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
擷取類中的構造方法
getConstructor(A.class):取得類的構造方法(不能擷取私有構造方法)
用法(位元組碼.getConstructor(A.class)),如果有多個構造方法,傳入構造方法的所接收的類位元組碼,傳回值類型是Constructor類型
getDeclaredConstructors():取得類中的所有構造方法(無論是私有還是公有)
用法(位元組碼.getDeclaredConstructors()),傳回值類型是Constructor數組
PS:通過getDeclaredConstructors()擷取私有的構造方法,可以突破單例模式不能建立對象的限制,由外部建立對象
代碼示例:
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = (String)constructor1.newInstance(/*"abc"*/new StringBuffer("abc"));
System.out.println(str2.charAt(2));
例:得到String的構造方法 :String.class.getConstructor()
String有不止一個構造方法,要得到哪一個構造方法,如何指定?
在getConstructor()中傳入參數,傳入的參數同樣為位元組碼,想得到的構造方法有幾個對象就傳幾個位元組碼檔案
如:String.class.getConstructor(StringBuffer.class)//這個就是得到參數為類型為StringBuffer.的構造方法
擷取方法的參數類型
Type[] getGenericParameterTypes():按照聲明順序傳回Type對象的數組,這些對象描述了此 Method 對象所表示的方法的形參類型的。如果底層方法不帶參數,則傳回長度為 0的數組。
用法:Type[] types = method. getGenericParameterTypes();
Field:類中的成員變量
取得某個類的某個成員變量:getFields(“name”),傳入的name是成員的名字,但這種隻能得到公有的成員,私有的不行(得到的隻是變量,但是并不是得到變量的值,要得到變量的值要得到該變量後,再通過get(指定對象)包括父類中的定義的成員
要修改值用set(指定對象)
擷取類中的成員變量
per.class.getFields(“age”),這樣就得到了Person這個類的成員變量age,并不是得到age的值
getDeclaredField():也是得到成員變量,與getFields(“name”)的差別在于:無論公有私有都可以得到,不受權限的控制
代碼:
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ReflectTest {
public static void main(String[] args) throws Exception {
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y");
//fieldY的值是多少?是5,錯!fieldY不是對象身上的變量,而是類上,要用它去取某個對象上對應的值
System.out.println(fieldY.get(pt1));
Field fieldX = pt1.getClass().getDeclaredField("x");
fieldX.setAccessible(true);
System.out.println(fieldX.get(pt1));
changeStringValue(pt1);
System.out.println(pt1);
}
public class ReflectPoint {
private Date birthday = new Date();
private int x;
public int y;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "itcast";
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ReflectPoint other = (ReflectPoint) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
@Override
public String toString(){
return str1 + ":" + str2 + ":" + str3;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
練習(重點):得到一個類中的String類型的成員變量,并把成員變量的值中的a用e來替換
private static void changeValue(Object obj)
{//注釋為思路與步驟
Field[] field = objgetClass.getFields();//得到所有的成員變量的數組
For(Field field: Field)//周遊該數組,取出成員變量
{
if(field.getType()==String.class)//判斷取出的成員變量是否是String類型的
{
String oldValue = field.get(obj);//取出obj該對象的String成員變量的值
String newValue = oldValue.replace(“a”,”e”);//替換字母後傳回一個新的字元串
field.set(obj,newValue);//設定obj對象的String成員變量的新值
}
}
}
---------------------- ASP.Net+Android+IOS開發、.Net教育訓練、期待與您交流! ----------------------
詳細請檢視:http://edu.csdn.net