1.理解反射的基礎(chǔ):Class類
眾所周知Java有個(gè)Object 類,是所有Java 類的繼承根源,其內(nèi)聲明了數(shù)個(gè)應(yīng)該在所有Java 類中被改寫的方法:hashCode()、equals()、clone()、toString()、getClass()等。其中g(shù)etClass()返回一個(gè)Class 對(duì)象。
Class 類十分特殊。它和一般類一樣繼承自O(shè)bject,其實(shí)體用以表達(dá)Java程序運(yùn)行時(shí)的classes和interfaces,也用來(lái)表達(dá)enum、array、primitive Java types(boolean, byte, char, short, int, long, float, double)以及關(guān)鍵詞void。當(dāng)一個(gè)class被加載,或當(dāng)加載器(class loader)的defineClass()被JVM調(diào)用,JVM 便自動(dòng)產(chǎn)生一個(gè)Class 對(duì)象。如果您想借由“修改Java標(biāo)準(zhǔn)庫(kù)源碼”來(lái)觀察Class 對(duì)象的實(shí)際生成時(shí)機(jī)(例如在Class的constructor內(nèi)添加一個(gè)println()),這樣是行不通的!因?yàn)镃lass并沒(méi)有public constructor。
Class是Reflection故事起源。針對(duì)任何您想探勘的類,唯有先為它產(chǎn)生一個(gè)Class 對(duì)象,接下來(lái)才能經(jīng)由后者喚起為數(shù)十多個(gè)的Reflection APIs。這些APIs將在稍后的探險(xiǎn)活動(dòng)中一一亮相。
Java類用于描述一類事物的共性,該類事物有什么屬性,至于這個(gè)類的屬性值是什么,則是由這個(gè)類的對(duì)象來(lái)確定,不同的實(shí)例對(duì)象有不同的屬性值。java程序中的各個(gè)類,他們也屬于同一類事物,也可以用一個(gè)類來(lái)描述這類事物,這個(gè)類就是Class,要注意和小寫的class關(guān)鍵字的區(qū)別。Class類描述那些方面的信息呢?類的名字,類的訪問(wèn)屬性,類所屬于的包名,字段名稱的列表,方法名稱的列表,等等,學(xué)習(xí)反射,首先要明白這個(gè)Class類。
對(duì)比提問(wèn)1:眾多的人用一個(gè)什么類表示?眾多的java類用什么表示?
人-》Person
Java類-》Class
此時(shí)很明顯的體現(xiàn)了java面向?qū)ο蟮乃枷耄ㄒ磺薪詾閷?duì)象)。
對(duì)比提問(wèn)2:Person類代表人,他的實(shí)例對(duì)象就是張三,李四這樣一個(gè)個(gè)具體的人,Class類代表java類,那么他的實(shí)例對(duì)象又分別對(duì)應(yīng)什么呢?
對(duì)應(yīng)的是各個(gè)類在內(nèi)存中的字節(jié)碼(一個(gè)類有且僅有一份),例如,Person類的字節(jié)碼,ArrayList類的字節(jié)碼等等。(字節(jié)碼就是類被加載到j(luò)vm中內(nèi)存中的Class類的實(shí)例,然后利用這個(gè)字節(jié)碼復(fù)制一個(gè)個(gè)指定類的對(duì)象)。
一個(gè)類被類加載器加載到內(nèi)存中,占用一片存儲(chǔ)空間,這個(gè)空間里邊的內(nèi)容就是類的字節(jié)碼,不同的類的字節(jié)碼是不同的,所以他在內(nèi)存中的內(nèi)容是不同的,這一個(gè)個(gè)的空間分別用一個(gè)個(gè)對(duì)象來(lái)表示,這些對(duì)象顯示具有相同的類型,這個(gè)類型是什么呢?就是 Class類。
三種獲取Class對(duì)象的方法:
不能用Class c = new Class(),沒(méi)有這個(gè)構(gòu)造方法的,應(yīng)該采取下邊的三種方法:
1). Person.class 類名.class的方式;
2). Person p = new Person; p.getClass(); person類的實(shí)例getClass的方式;
3). Class.forName(“類名(全路徑)”); 這個(gè)如果在jvm內(nèi)存中沒(méi)有找到指定類的字節(jié)碼,就先將指定類加載到j(luò)vm內(nèi)存中,然后在返回指定的類的Class實(shí)例,如果jvm中存在就直接返回。
需要注意的是:一般實(shí)現(xiàn)反射的話都是使用第三種方式Class.forName(“”).因?yàn)檫@個(gè)參數(shù)可以寫成變量傳進(jìn)來(lái),此時(shí)就可以讀取配置文件的字符串來(lái)動(dòng)態(tài)的獲取相關(guān)類的字節(jié)碼實(shí)例。
/**
* 獲取一個(gè)類的字節(jié)碼對(duì)象的三種方法 同一個(gè)類,類實(shí)例(字節(jié)碼對(duì)象)在jvm中有且只有一份
*
* @throws ClassNotFoundException
*/
@Test
public void test1() throws ClassNotFoundException {
String str = "abc";
// 表示返回此對(duì)象運(yùn)行時(shí)類的 Class對(duì)象
Class<? extends String> cls1 = str.getClass();
// 編譯器通過(guò)String就可以確定返回String類型的Class對(duì)象。
Class<String> cls2 = String.class;
// 給編譯器看的,編譯器并不知道通過(guò)forName會(huì)返回什么類型的Class對(duì)象
Class<?> cls3 = Class.forName("java.lang.String");
System.out.println(cls1 == cls2); // true
System.out.println(cls1 == cls3); // true
}
由輸出結(jié)果可知,每個(gè)類不管使用三種方式中的哪種方式來(lái)獲取Class對(duì)象都是一份,從而證明了內(nèi)存中同一個(gè)類的Class對(duì)象有且只有一份。
9個(gè)預(yù)定義的class對(duì)象:八種基本數(shù)據(jù)類型和void關(guān)鍵字。
/**
* 預(yù)定義的Class對(duì)象
*/
@Test
public void test2() {
Class<String> cls2 = String.class;
// primitive是原始的意思,判定指定的 Class對(duì)象是否表示一個(gè)基本類型(原始類型)
System.out.println(cls2.isPrimitive());
// 判定指定的 Class 對(duì)象是否表示一個(gè)基本類型
System.out.println(int.class.isPrimitive());
// 基本類型和對(duì)應(yīng)包裝類Class對(duì)象不是同一個(gè)
System.out.println(int.class == Integer.class); //false int和Integer包裝類不是同一份字節(jié)碼
/*
* Integer.TYPE代表的是integer包裝的基本類的字節(jié)碼
* 根據(jù)文檔:表示基本類型 int 的 Class 實(shí)例
*/
System.out.println(int.class == Integer.TYPE); //true
//數(shù)組有對(duì)應(yīng)的數(shù)組類(Array類)
System.out.println(int[].class.isPrimitive()); //false
// 是不是數(shù)組類class對(duì)象
System.out.println(int[].class.isArray());
}
2.反射的概念
JAVA反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意方法和屬性;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱為java語(yǔ)言的反射機(jī)制。
JAVA反射(放射)機(jī)制:“程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語(yǔ)言稱為動(dòng)態(tài)語(yǔ)言”。從這個(gè)觀點(diǎn)看,Perl,Python,Ruby是動(dòng)態(tài)語(yǔ)言,C++,Java,C#不是動(dòng)態(tài)語(yǔ)言。但是JAVA有著一個(gè)非常突出的動(dòng)態(tài)相關(guān)機(jī)制:Reflection,用在Java身上指的是我們可以于運(yùn)行時(shí)加載、探知、使用編譯期間完全未知的classes。換句話說(shuō),Java程序可以加載一個(gè)運(yùn)行時(shí)才得知名稱的class,獲悉其完整構(gòu)造(但不包括methods定義),并生成其對(duì)象實(shí)體、或?qū)ζ鋐ields設(shè)值、或喚起其methods.
Java反射機(jī)制主要提供了以下功能: 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類;在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象;在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法;在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法;生成動(dòng)態(tài)代理。
反射就是把java類中的各個(gè)成分映射成相應(yīng)的java類。
例如:一個(gè)java類中用一個(gè)Class類的對(duì)象來(lái)表示,一個(gè)類中的組成部分:成員變量,方法,構(gòu)造方法,包等信息也用一個(gè)個(gè)的java類來(lái)表示,就像汽車是一個(gè)類,汽車中的發(fā)動(dòng)機(jī),變速箱等等也是一個(gè)個(gè)的類。表示java類的Class類顯然要提供一些方法來(lái)獲取其中的變量,方法,構(gòu)造方法,修飾符,包等信息,這些信息就是用相應(yīng)類的實(shí)例對(duì)象來(lái)表示,他們是Filed,Method,Constructor,Package等等。(可以查看Class類的api就可以了解相關(guān)的方法)。
一個(gè)類的每個(gè)成員都可以用相應(yīng)的反射API類的一個(gè)實(shí)例對(duì)象來(lái)表示,通過(guò)調(diào)用Class類的方法可以得到這些實(shí)例對(duì)象后,得到這些實(shí)例對(duì)象后有什么用呢?怎么用呢?這才是要點(diǎn)。
反射在很多地方都能用到,比如Spring(一個(gè)開(kāi)放源代碼的設(shè)計(jì)層面框架),Struts(一個(gè)基于MVC設(shè)計(jì)模式的Web應(yīng)用框架),JUnit(一個(gè)Java語(yǔ)言的單元測(cè)試框架)等一些框架中,反射是框架設(shè)計(jì)的靈魂。
3.構(gòu)造方法的反射
Constructor類代表某個(gè)類中的一個(gè)構(gòu)造方法。
/**
* 構(gòu)造方法的反射
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InvocationTargetException
*/
@Test
public void test3() throws NoSuchMethodException, SecurityException,
InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Class<String> clazz = String.class;
//獲取String類的所有構(gòu)造方法
Constructor<?>[] constructors = clazz.getConstructors();
/*
* 通過(guò)構(gòu)造函數(shù)反射實(shí)例化對(duì)象
*/
String str1 = new String(new StringBuffer("adc"));
Constructor<String> constructor1 = String.class
.getConstructor(StringBuffer.class);
String str2 = constructor1.newInstance(new StringBuffer("abc"));
//使用默認(rèn)的構(gòu)造方法實(shí)例化對(duì)象,newInstance
String str3 = String.class.newInstance();
}
使用newInstance方法來(lái)實(shí)例化對(duì)象的情況,newInstance方法先得到相應(yīng)類的默認(rèn)的構(gòu)造方法,然后使用該默認(rèn)的構(gòu)造方法來(lái)實(shí)例化對(duì)象。
通過(guò)查看源碼知:java會(huì)用緩存機(jī)制來(lái)緩存默認(rèn)的構(gòu)造方法實(shí)例,由此可以看出用了緩存說(shuō)明獲取Constructor對(duì)象是一個(gè)很耗時(shí)的操作。
擴(kuò)展:因?yàn)榉瓷錂C(jī)制的存在,所以單例模式并不能完全保證單例對(duì)象的唯一性。如何保證單例防反射攻擊,請(qǐng)看這篇: 單例模式--反射--防止序列化破壞單例模式
4.成員變量的反射
Filed類代表某個(gè)類中的一個(gè)成員變量,即某個(gè)類的字節(jié)碼對(duì)象的字段對(duì)象,不和具體的類的實(shí)例對(duì)應(yīng)。
public class ReflectPoint {
private Date birthday = new Date();
private int x;
public int y;
public String str1;
public String str2;
public String str3;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
public ReflectPoint(String str1, String str2, String str3) {
super();
this.str1 = str1;
this.str2 = str2;
this.str3 = str3;
}
@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;
}
}
/**
* 成員變量的反射
* @throws SecurityException
* @throws NoSuchFieldException
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
@Test
public void test4() throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
ReflectPoint pt1 = new ReflectPoint(3, 5);
Class<? extends ReflectPoint> clazz = pt1.getClass();
/*
* 獲取指定的字段對(duì)象
* fieldY的值是多少?是5,錯(cuò)!fieldY不是對(duì)象身上的變量,而是類上,要用它去取某個(gè)對(duì)象上對(duì)應(yīng)的值
*/
Field fieldY = clazz.getField("y");
//獲取pt1對(duì)象上的y字段的值
System.out.println("變量Y的值:" + fieldY.getInt(pt1));
/*
* getField只能獲取public和defalut修飾的字段,此時(shí)x是私有變量。
*/
/*
* Field fieldX = clazz.getField("x");
* System.out.println(fieldX.getInt(pt1));
*/
/*
* getDeclaredFields可以獲取類中所有的成員變量 包括私有的變量
*/
Field[] fields = clazz.getDeclaredFields();
System.out.println("成員變量個(gè)數(shù):" + fields.length);
/*
* 獲取私有變量x的值
* 雖然獲取到x了,但是沒(méi)有權(quán)限訪問(wèn)其中的值,所以需要設(shè)置x字段對(duì)象為可以訪問(wèn)的。
*/
Field fieldX = clazz.getDeclaredField("x");
fieldX.setAccessible(true);
System.out.println("變量X的值:" + fieldX.getInt(pt1));
}
/**
* 成員變量反射的綜合案例 將任意一個(gè)對(duì)象中的所有String類型的成員變量所對(duì)應(yīng)的字段內(nèi)容中的“b”改成”a”
* @throws SecurityException
* @throws NoSuchFieldException
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
@Test
public void test5() throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
ReflectPoint pt1 = new ReflectPoint("ball", "basketball", "itcast");
System.out.println("修改前:");
System.out.println(pt1.str1);
System.out.println(pt1.str2);
System.out.println(pt1.str3);
Class<? extends ReflectPoint> clazz = pt1.getClass();
// /Field fieldX = clazz.getDeclaredField("x");
Field[] fields = clazz.getDeclaredFields(); //獲取所有的字段 包括私有字段
for (Field field : fields) {
/*
* 獲取字段的類型(返回的是類型的字節(jié)碼實(shí)例) 判斷是否和String類的字節(jié)碼相等就能判斷是否是String類型的字段了。
* 因?yàn)樽止?jié)碼只有一個(gè),所以使用 == 比使用equeals更能體現(xiàn)意義
*/
Class<?> filedType = field.getType();
if (filedType == String.class) {
field.setAccessible(true);
String oldValue = (String) field.get(pt1);
String newValue = oldValue.replace("b", "a");
field.set(pt1, newValue); //重新將替換后的新值set到相關(guān)到對(duì)象中去。
}
}
System.out.println("修改后:");
System.out.println(pt1.str1);
System.out.println(pt1.str2);
System.out.println(pt1.str3);
}
結(jié)論:
從上可以看出對(duì)于一些對(duì)象,可以使用反射將其中的值都改掉,Spring實(shí)例化里邊的值和初始化對(duì)象的值都是如此實(shí)現(xiàn)的。
5.成員方法的反射
Method類代表某個(gè)類中的一個(gè)成員方法。
/**
* 成員方法的反射
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
@Test
public void test6() throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
String str = "abc";
//獲取指定方法的Method類的實(shí)例
Method method = String.class.getMethod("charAt", int.class);
//調(diào)用指定實(shí)例的方法,并傳參
//如果是Method代表的是靜態(tài)方法,那么第一參數(shù)為null
System.out.println(method.invoke(str, 1));
}
6.對(duì)接收數(shù)組參數(shù)的成員方法進(jìn)行反射
問(wèn)題:
用反射的方式執(zhí)行某個(gè)類中的main方法,寫一個(gè)程序,根據(jù)用戶提供的類名,去執(zhí)行該類的main方法。如果使用傳統(tǒng)的方式執(zhí)行main方法可以直接Test.main(new String[]{}); 但是不能動(dòng)態(tài)指定類名(用戶提供的),因?yàn)閭鹘y(tǒng)的方式都已經(jīng)編譯了不能再改了。
/**
* 對(duì)接收數(shù)組參數(shù)的成員方法進(jìn)行反射 用反射的方式執(zhí)行某個(gè)類中的main方法,寫一個(gè)程序,根據(jù)用戶提供的類名,去執(zhí)行該類的main方法。
*
* @throws ClassNotFoundException
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
@Test
public void test7() throws ClassNotFoundException, NoSuchMethodException,
SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
String mainStr = "mytest.TestArguments";
Method mainMethod = Class.forName(mainStr).getMethod("main",
String[].class);
mainMethod.invoke(null, new String[] { "a", "b", "c" });
}
/**
* 測(cè)試反射main方法的類
*/
class TestArguments {
public static void main(String[] args) {
for (String arg : args) {
System.out.println(arg);
}
}
}
上述代碼報(bào)錯(cuò):java.lang.IllegalArgumentException: wrong number of arguments
明顯是參數(shù)個(gè)數(shù)錯(cuò)誤,main方法確實(shí)需要一個(gè)參數(shù),而我也傳了一個(gè)參數(shù),為什么會(huì)錯(cuò)呢?
因?yàn)樵跒閕nvoke傳遞數(shù)組類型的參數(shù)的時(shí)候,按照jdk1.5的做法,整個(gè)數(shù)組是一個(gè)參數(shù),而按照jdk1.4的語(yǔ)法,會(huì)將數(shù)組拆開(kāi),每個(gè)元素對(duì)應(yīng)一個(gè)參數(shù),所以當(dāng)把一個(gè)字符串?dāng)?shù)組作為一個(gè)參數(shù)傳遞給invoke方法時(shí),javac會(huì)按照哪種方法進(jìn)行處理呢?jdk1.5肯定要兼容jdk1.4的做法,會(huì)先按照1.4的語(yǔ)法處理,即把數(shù)組拆開(kāi)為每一個(gè)元素作為一個(gè)參數(shù)。所以如果按照上邊的方式會(huì)出現(xiàn)異常。可以采用下邊的方式:
/**
* 對(duì)接收數(shù)組參數(shù)的成員方法進(jìn)行反射 用反射的方式執(zhí)行某個(gè)類中的main方法,寫一個(gè)程序,根據(jù)用戶提供的類名,去執(zhí)行該類的main方法。
* @throws ClassNotFoundException
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
*/
@Test
public void test7() throws ClassNotFoundException, NoSuchMethodException,
SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
String mainStr2 = "mytest.TestArguments";
Method mainMethod2 = Class.forName(mainStr2).getMethod("main",
String[].class);
/*
* jdk1.4的做法
* 重新包裝字符串?dāng)?shù)組為一個(gè)object數(shù)組,此時(shí)按照1.4的方式拆開(kāi)之后只有一個(gè)參數(shù)就是里邊的string數(shù)組
*/
mainMethod2
.invoke(null, new Object[] { new String[] { "a", "b", "c" } });
/*
* jdk1.5的做法
* 重新包裝字符串?dāng)?shù)組為一個(gè)object,此時(shí)給invoke方法傳遞的參數(shù)不是數(shù)組,編譯器不會(huì)去拆解了,
* (數(shù)組也是Object)
*/
mainMethod2.invoke(null, (Object) new String[] { "a", "b", "c" });
}
7.數(shù)組與Object的關(guān)系及數(shù)組的反射類型
根據(jù)文檔中class的解釋,對(duì)于數(shù)組的Class對(duì)象實(shí)例,具有相同維數(shù)(一維數(shù)組二維數(shù)組等)和元素類型的屬于同一個(gè)類型,即具有相同的Class實(shí)例對(duì)象。中文文檔的說(shuō)明:所有具有相同元素類型和維數(shù)的數(shù)組都共享該 Class 對(duì)象。
int[] a1 = new int[] { 1, 2, 3 };
Integer[] a11 = new Integer[] { 1, 2, 3 };
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[] { "a", "b", "c" };
System.out.println(a1.getClass() == a2.getClass()); // true
// 都是一維數(shù)組,但是數(shù)組元素類型不一致,直接編譯不通過(guò)。
// System.out.println(a1.getClass() == a4.getClass());
// 數(shù)組元素類型以致,但是維數(shù)不同,直接編譯不通過(guò)。
// System.out.println(a1.getClass() == a3.getClass());
數(shù)組的反射類型的name:
/*
* 基本類型的數(shù)組getName
*/
//[I
System.out.println("int[]:" + a1.getClass().getName());
//int
System.out.println("int:" + int.class.getName());
/*
* 引用類型的數(shù)組getName
*/
// [Ljava.lang.String;
System.out.println("String[]:" + a4.getClass().getName());
// java.lang.String
System.out.println("String:" + String.class.getName());
/*
* 與getName相對(duì)應(yīng)的是forName
* 根據(jù)數(shù)組類型的Name類獲取Class
*/
// 基本類型
Class<?> c1 = Class.forName("[I");
System.out.println(c1.isArray()); // true
// 引用類型
Class<?> c2 = Class.forName("[Ljava.lang.String;");
System.out.println(c2.isArray()); // true
對(duì)于"[I"中,[表示數(shù)組,I表示數(shù)組元素類型是int。
具體I代表什么參考getName方法的api注釋:
基礎(chǔ)類型:
Element Type Encoding
boolean Z
byte B
char C
double D
float F
int I
long J
short S
引用類型:
Element Type Encoding
class or interface Lclassname;
例子:
String.class.getName()
returns "java.lang.String"
byte.class.getName()
returns "byte"
(new Object[3]).getClass().getName()
returns "[Ljava.lang.Object;"
(new int[3][4][5][6][7][8][9]).getClass().getName()
returns "[[[[[[[I"
getSimpleName方法
// String
System.out.println(String.class.getSimpleName());
// int[]
System.out.println(a1.getClass().getSimpleName());
8.數(shù)組的反射應(yīng)用
數(shù)組不是類,但是實(shí)現(xiàn)了Object中的方法。
按照J(rèn)ava語(yǔ)言規(guī)范的說(shuō)法,Java數(shù)據(jù)類型分為兩大類:基本數(shù)據(jù)類型和復(fù)合數(shù)據(jù)類型,其中復(fù)合數(shù)據(jù)類型包括數(shù)組、類和接口。
Array類(Array工具類)完成對(duì)數(shù)組的反射,是代表了對(duì)于數(shù)組類的描述。文檔中說(shuō)明:Array 類提供了動(dòng)態(tài)創(chuàng)建和訪問(wèn) Java 數(shù)組的方法。
擴(kuò)展 : java.lang.reflect包