JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制(注意關鍵詞:執行狀態)換句話說,Java程式可以載入一個執行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),並生成其物件實體、或對其fields設值、或喚起其methods
反射機制主要提供的功能
- 在執行時判斷任意一個物件所屬的類;
- 在執行時構造任意一個類的物件;
- 在執行時判斷任意一個類所具有的成員變數和方法;
- 在執行時呼叫任意一個物件的方法;
java Reflection API簡介
- Class類:代表一個類,位於java.lang包下
- Field類:代表類的成員變數(成員變數也稱為類的屬性)
- Method類:代表類的方法
- Constructor類:代表類的構造方法
- Array類:提供了動態建立陣列,以及訪問陣列的元素的靜態方法
java中的Class介紹
Class 類十分特殊,它沒有共有的構造方法,被jvm呼叫的(簡單的理解:new物件或者被類載入器載入的時候),在Java中,每個class都有一個相應的Class物件。也就是說,當我們編寫一個類,編譯完成後,在生成的.class檔案中,就會產生一個Class物件,用於表示這個類的型別資訊。
java中的Class三種獲取方式
- 利用物件呼叫getClass()方法獲取該物件的Class例項;
- 使用Class類的靜態方法forName(),用類的名字獲取一個Class例項 ;
- 運用.class的方式來獲取Class例項,對於基本資料型別的封裝類,還可以採用.TYPE來獲取相對應的基本資料型別的Class例項;
說明:在執行期間,如果我們要產生某個類的物件,Java虛擬機器(JVM)會檢查該型別的Class物件是否已被載入。如果沒有被載入,JVM會根據類的名稱找到.class檔案並載入它。一旦某個型別的Class物件已被載入到記憶體,就可以用它來產生該型別的所有物件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //方式一 Person person = new Person(); Class<? extends Person> personClazz01 = person.getClass(); //方式二 try { Class<?> personClazz02 = Class.forName("Person"); } catch (ClassNotFoundException e) { e.printStackTrace(); } //方式三 Class<? extends Person> personClazz03 = Person.class; |
java中的Class中一些重要的方法
public Annotation[] getAnnotations () 獲取這個類中所有註解
getClassLoader() 獲取載入這個類的類載入器
getDeclaredMethods() 獲取這個類中的所有方法
getReturnType() 獲取方法的返回型別
getParameterTypes() 獲取方法的傳入引數型別
isAnnotation() 測試這類是否是一個註解類
getDeclaredConstructors() 獲取所有的構造方法
getDeclaredMethod(String name, Class… parameterTypes) 獲取指定的構造方法(引數:引數型別.class)
getSuperclass() 獲取這個類的父類
getInterfaces() 獲取這個類實現的所有介面
getFields() 獲取這個類中所有被public修飾的成員變數
getField(String name) 獲取指定名字的被public修飾的成員變數
newInstance() 返回此Class所表示的類,通過呼叫預設的(即無引數)建構函式建立的一個新例項
等等方法
如何通過反射獲取私有成員變數和私有方法
Person類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
/**
* Created by yuanyc on 2016/1/28.
*/
public
class
Person
{
private
String
name
=
"zhangsan";
private
String
age;
public
String
getName()
{
return
name;
}
public
void
setName(String
name)
{
this.name
=
name;
}
}
Person
person
=
new
Person();
//列印沒有改變屬性之前的name值
System.out.println("before:"
+
getPrivateValue(person,
"name"));
person.setName("lisi");
//列印修改之後的name值
System.out.println("after:"
+
getPrivateValue(person,
"name"));
/**
* 通過反射獲取私有的成員變數
*
* @param person
* @return
*/
private
Object
getPrivateValue(Person
person,
String
fieldName)
{
try
{
Field
field
=
person.getClass().getDeclaredField(fieldName);
//
引數值為true,開啟禁用訪問控制檢查
//setAccessible(true)
並不是將方法的訪問許可權改成了public,而是取消java的許可權控制檢查。
//所以即使是public方法,其accessible
屬相預設也是false
field.setAccessible(true);
return
field.get(person);
}
catch
(Exception
e)
{
e.printStackTrace();
}
return
null;
}
|
獲取私有方法的方式類似獲取私有成員變數的方式
Filed類,Method類等詳細檢視開發者文件:
http://developer.android.com/intl/zh-cn/reference/java/lang/reflect/Field.html
案例演示反射
Person類
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /** * Created by yuanyc on 2016/1/28. */ public class Person { private int age; private String name; public Person(){ } public Person(int age, String name){ this.age = age; this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } } |
SuperPerson類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/**
* Created by yuanyc on 2016/1/28.
*/
public
class
SuperPerson
extends
Person
implements
Smoke.Smoking{
private
boolean
isMan;
public
void
fly()
{
System.out.println("走你~~");
}
public
boolean
isMan()
{
return
isMan;
}
public
void
setMan(boolean
iaMan)
{
isMan
=
iaMan;
}
@Override
public
void
smoke(int
count)
{
}
}
|
Smoke介面類
1 2 3 4 5 6 7 8 9 | /** * Created by yuanyc on 2016/1/28. */ public class Smoke { public interface Smoking { public void smoke(int count); } } |
MainActivity類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
public
class
MainActivity
extends
Activity
{
@Override
protected
void
onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Tests();
}
private
void
Tests()
{
try
{
//通過Java反射機制得到類的包名和類名
Test1();
System.out.println("===============================================");
//驗證所有的類都是Class類的例項物件
Test2();
System.out.println("===============================================");
//通過Java反射機制,用Class
建立類物件[這也就是反射存在的意義所在],無參構造
Test3();
System.out.println("===============================================");
//通過Java反射機制得到一個類的建構函式,並實現構造帶參例項物件
Test4();
System.out.println("===============================================");
//通過Java反射機制操作成員變數,
set 和 get
Test5();
System.out.println("===============================================");
//通過Java反射機制得到類的一些屬性:
繼承的介面,父類,函式資訊,成員資訊,型別等
Test6();
System.out.println("===============================================");
//通過Java反射機制呼叫類中方法
Test7();
System.out.println("===============================================");
//通過Java反射機制獲得類載入器
Test8();
System.out.println("===============================================");
}
catch
(Exception
e)
{
e.printStackTrace();
}
}
/**
* Demo1: 通過Java反射機制得到類的包名和類名
*/
public
static
void
Test1()
{
Person
person
=
new
Person();
System.out.println("Test1:
包名: "
+
person.getClass().getPackage().getName()
+
","
+
"完整類名: "
+
person.getClass().getName());
}
/**
* Demo2: 驗證所有的類都是Class類的例項物件
*/
public
static
void
Test2()
throws
ClassNotFoundException
{
//定義兩個型別都未知的Class
, 設定初值為null, 看看如何給它們賦值成Person類
Class<?>
class1
=
null;
Class<?>
class2
=
null;
//寫法1,
可能丟擲 ClassNotFoundException [多用這個寫法]
class1
=
Class.forName("com.tuba.yuanyc.audiomanagerdemo.Person");
System.out.println("Test2:(寫法1)
包名: "
+
class1.getPackage().getName()
+
","
+
"完整類名: "
+
class1.getName());
//寫法2
class2
=
Person.class;
System.out.println("Test2:(寫法2)
包名: "
+
class2.getPackage().getName()
+
","
+
"完整類名: "
+
class2.getName());
}
/**
* Demo3: 通過Java反射機制,用Class 建立類物件[這也就是反射存在的意義所在]
*/
public
static
void
Test3()
throws
ClassNotFoundException,
InstantiationException,
IllegalAccessException
{
Class<?>
class1
=
null;
class1
=
Class.forName("com.tuba.yuanyc.audiomanagerdemo.Person");
//由於這裡不能帶引數,所以你要例項化的這個類Person,一定要有無參建構函式
Person
person
=
(Person)
class1.newInstance();
person.setAge(27);
person.setName("yyc");
System.out.println("Test3:
"
+
person.getName()
+
" : "
+
person.getAge());
}
/**
* Demo4: 通過Java反射機制得到一個類的建構函式,並實現建立帶參例項物件
*/
public
static
void
Test4()
throws
ClassNotFoundException,
IllegalArgumentException,
InstantiationException,
IllegalAccessException,
InvocationTargetException
{
Class<?>
class1
=
null;
Person
person1
=
null;
Person
person2
=
null;
class1
=
Class.forName("com.tuba.yuanyc.audiomanagerdemo.Person");
//得到一系列建構函式集合
Constructor<?>[]
constructors
=
class1.getConstructors();
try
{
person1
=
(Person)
constructors[0].newInstance();
}
catch
(InvocationTargetException
e)
{
e.printStackTrace();
}
person1.setAge(28);
person1.setName("yyc");
person2
=
(Person)
constructors[1].newInstance(29,
"yyc");
System.out.println("Test4:
"
+
person1.getName()
+
" : "
+
person1.getAge()
+
" , "
+
person2.getName()
+
" : "
+
person2.getAge());
}
/**
* Demo5: 通過Java反射機制操作成員變數, set 和 get
*/
public
static
void
Test5()
throws
IllegalArgumentException,
IllegalAccessException,
SecurityException,
NoSuchFieldException,
InstantiationException,
ClassNotFoundException
{
Class<?>
class1
=
null;
class1
=
Class.forName("com.tuba.yuanyc.audiomanagerdemo.Person");
Object
obj
=
class1.newInstance();
Field
nameField
=
class1.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj,
"cyy");
System.out.println("Test5:
修改屬性之後得到屬性變數的值:"
+
nameField.get(obj));
}
/**
* Demo6: 通過Java反射機制得到類的一些屬性: 繼承的介面,父類,函式資訊,成員資訊,型別等
*/
public
static
void
Test6()
throws
ClassNotFoundException
{
Class<?>
class1
=
null;
class1
=
Class.forName("com.tuba.yuanyc.audiomanagerdemo.Person");
//取得父類名稱
Class<?>
superClass
=
class1.getSuperclass();
System.out.println("Test6: SuperMan類的父類名:
"
+
superClass.getName());
System.out.println("===============================================");
Field[]
fields
=
class1.getDeclaredFields();
for
(int
i
=
0;
i
<
fields.length;
i++)
{
System.out.println("類中的成員:
"
+
fields[i]);
}
System.out.println("===============================================");
//取得類方法
Method[]
methods
=
class1.getDeclaredMethods();
for
(int
i
=
0;
i
<
methods.length;
i++)
{
System.out.println("Test6,取得SuperMan類的方法:");
System.out.println("函式名:"
+
methods[i].getName());
System.out.println("函式返回型別:"
+
methods[i].getReturnType());
System.out.println("函式訪問修飾符:"
+
Modifier.toString(methods[i].getModifiers()));
System.out.println("函式程式碼寫法:
"
+
methods[i]);
}
System.out.println("===============================================");
Class<?>
interfaces[]
=
class1.getInterfaces();
for
(int
i
=
0;
i
<
interfaces.length;
i++)
{
System.out.println("實現的介面類名:
"
+
interfaces[i].getName());
}
}
/**
* Demo7: 通過Java反射機制呼叫類方法
*/
public
static
void
Test7()
throws
ClassNotFoundException,
SecurityException,
NoSuchMethodException,
IllegalArgumentException,
IllegalAccessException,
InvocationTargetException,
InstantiationException
{
Class<?>
class1
=
null;
class1
=
Class.forName("com.tuba.yuanyc.audiomanagerdemo.SuperPerson");
System.out.println("Test7:
\n呼叫無參方法fly():");
Method
method
=
class1.getMethod("fly");
method.invoke(class1.newInstance());
System.out.println("呼叫有參方法smoke(int
m):");
method
=
class1.getMethod("smoke",
int.class);
method.invoke(class1.newInstance(),
100);
}
/**
* Demo8: 通過Java反射機制得到類載入器資訊
* <p/>
* 在java中有三種類類載入器。
* <p/>
* 1)Bootstrap ClassLoader 此載入器採用c++編寫,一般開發中很少見。
* <p/>
* 2)Extension ClassLoader 用來進行擴充套件類的載入,一般對應的是jre\lib\ext目錄中的類
* <p/>
* 3)AppClassLoader 載入classpath指定的類,是最常用的載入器。同時也是java中預設的載入器。
*
* @throws ClassNotFoundException
*/
public
static
void
Test8()
throws
ClassNotFoundException
{
Class<?>
class1
=
null;
class1
=
Class.forName("com.tuba.yuanyc.audiomanagerdemo.SuperPerson");
String
name
=
class1.getClassLoader().getClass().getName();
System.out.println("Test8:
類載入器類名: "
+
name);
}
}
|
執行結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test1:
包名:
com.tuba.yuanyc.audiomanagerdemo,完整類名:
com.tuba.yuanyc.audiomanagerdemo.Person
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
===============================================
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test2:(寫法1)
包名:
com.tuba.yuanyc.audiomanagerdemo,完整類名:
com.tuba.yuanyc.audiomanagerdemo.Person
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test2:(寫法2)
包名:
com.tuba.yuanyc.audiomanagerdemo,完整類名:
com.tuba.yuanyc.audiomanagerdemo.Person
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
===============================================
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test3:
yyc
:
27
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
===============================================
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test4:
yyc
:
28 ,
yyc
:
29
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
===============================================
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test5:
修改屬性之後得到屬性變數的值:cyy
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
===============================================
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test6: SuperMan類的父類名:
java.lang.Object
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
===============================================
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
類中的成員:
private
java.lang.String
com.tuba.yuanyc.audiomanagerdemo.Person.name
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
類中的成員:
private
int
com.tuba.yuanyc.audiomanagerdemo.Person.age
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
===============================================
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test6,取得SuperMan類的方法:
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式名:getAge
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式返回型別:int
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式訪問修飾符:public
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式程式碼寫法:
public
int
com.tuba.yuanyc.audiomanagerdemo.Person.getAge()
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test6,取得SuperMan類的方法:
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式名:getName
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式返回型別:class
java.lang.String
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式訪問修飾符:public
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式程式碼寫法:
public
java.lang.String
com.tuba.yuanyc.audiomanagerdemo.Person.getName()
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test6,取得SuperMan類的方法:
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式名:setAge
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式返回型別:void
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式訪問修飾符:public
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式程式碼寫法:
public
void
com.tuba.yuanyc.audiomanagerdemo.Person.setAge(int)
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test6,取得SuperMan類的方法:
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式名:setName
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式返回型別:void
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式訪問修飾符:public
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
函式程式碼寫法:
public
void
com.tuba.yuanyc.audiomanagerdemo.Person.setName(java.lang.String)
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
===============================================
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
===============================================
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test7:
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
呼叫無參方法fly():
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
走你~~
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
呼叫有參方法smoke(int
m):
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
===============================================
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
Test8:
類載入器類名:
dalvik.system.PathClassLoader
01-28
17:19:29.463 14972-14972/?
I/System.out﹕
===============================================
|