反射
(Reflection)
,
JAVA
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为
java
语言的反射机制。
内省
(Introspector)
,是“看透
class
”的能力(内省、内观、反省)。
Java
允许我们从多种管道为一个
class
生成对应的
Class object
。
Class object
诞生管道
|
示例
|
运用
getClass()
注:每个
class
都有此函数
|
String str = "abc";
Class c1 = str.getClass();
|
运用
Class.getSuperclass()
2
|
Button b = new Button();
Class c1 = b.getClass();
Class c2 = c1.getSuperclass();
|
运用
static method
Class.forName()
(最常被使用)
|
Class c1 = Class.forName ("java.lang.String");
Class c2 = Class.forName ("java.awt.Button");
Class c3 = Class.forName ("java.util.LinkedList$Entry");
Class c4 = Class.forName ("I");
Class c5 = Class.forName ("[I");
|
运用
.class
语法
|
Class c1 = String.class;
Class c2 = java.awt.Button.class;
Class c3 = Main.InnerClass.class;
Class c4 = int.class;
Class c5 = int[].class;
|
运用
primitive wrapper classes
的
TYPE
语法
|
Class c1 = Boolean.TYPE;
Class c2 = Byte.TYPE;
Class c3 = Character.TYPE;
Class c4 = Short.TYPE;
Class c5 = Integer.TYPE;
Class c6 = Long.TYPE;
Class c7 = Float.TYPE;
Class c8 = Double.TYPE;
Class c9 = Void.TYPE;
|
图
1
:
Java
允许多种管道生成
Class object
。
以图
2
的
java.util.LinkedList
为例,将
Java class
的定义大卸八块,每一块分别对应图
3
所示的
Reflection API
。
package java.util; //(1)
import java.lang.*; //(2)
public class
LinkedList
<
E
> //(3)(4)(5)
extends
AbstractSequentialList
<E> //(6)
implements
List
<E>,
Queue
<E>,
Cloneable, java.io.Serializable //(7)
{
private static class
Entry
<E> {
…
}//(8)
public
LinkedList
() {
…
} //(9)
public
LinkedList
(Collection<? extends E> c) {
…
}
public E
getFirst
() {
…
} //(10)
public E
getLast
() {
…
}
private transient Entry<E>
header
=
…
; //(11)
private transient int
size
= 0;
}
图
2
:将一个
Java class
大卸八块,每块相应于一个或一组
Reflection APIs
(图
3
)。
图
2
的各个
Java class
成份,分别对应于图
3
的
Reflection API
,其中出现的
Package
、
Method
、
Constructor
、
Field
等等
classes
,都定义于
java.lang.reflect
。本表并非
Reflection APIs
的全部。
Java class
内部模块(参见
图
3
)
|
Java class
内部模块说明
|
相应之
Reflection API
,多半为
Class
methods
。
|
返回值类型
(return type)
|
(1) package
|
class
隶属哪个
package
|
getPackage()
|
Package
|
(2) import
|
class
导入哪些
classes
|
无直接对应之
API
。
解决办法见
图
5-2
。
|
|
(3) modifier
|
class
(或
methods, fields
)的属性
|
int getModifiers()
Modifier.toString(int)
Modifier.isInterface(int)
|
int
String
bool
|
(4) class name or interface name
|
class/interface
|
名称
getName()
|
String
|
(5) type parameters
|
参数化类型的名称
|
getTypeParameters()
|
TypeVariable <Class>[]
|
(6) base class
|
base class
(只可能一个)
|
getSuperClass()
|
Class
|
(7) implemented interfaces
|
实现有哪些
interfaces
|
getInterfaces()
|
Class[]
|
(8) inner classes
|
内部
classes
|
getDeclaredClasses()
|
Class[]
|
(8') outer class
|
如果我们观察的
class
本身是
inner classes
,那么相对它就会有个
outer class
。
|
getDeclaringClass()
|
Class
|
(9) constructors
|
构造函数
getDeclaredConstructors()
|
不论
public
或
private
或其它
access level
,皆可获得。另有功能近似之取得函数。
|
Constructor[]
|
(10) methods
|
操作函数
getDeclaredMethods()
|
不论
public
或
private
或其它
access level
,皆可获得。另有功能近似之取得函数。
|
Method[]
|
(11) fields
|
字段(成员变量)
|
getDeclaredFields()
不论
public
或
private
或其它
access level
,皆可获得。另有功能近似之取得函数。
|
Field[]
|
图
3
:
Java class
大卸八块后(如图
2
),每一块所对应的
Reflection API
。
Model.java
package
RefInt;
import
java.io.Serializable;
import
java.util.Date;
public
class
Model
implements
Serializable {
private
static
final
long
serialVersionUID
= -162798607158235676L;
public
static
String
id
=
"111111"
;
public
String
name
=
"haha"
;
private
int
age
;
private
Date
b
;
public
int
getAge() {
return
age
;
}
public
void
setAge(
int
age) {
this
.
age
= age;
}
public
Date getB() {
return
b
;
}
public
void
setB(Date b) {
this
.
b
= b;
}
public
String getName() {
return
name
;
}
public
void
setName(String name) {
this
.
name
= name;
}
}
RefInt.java
package
RefInt;
import
java.lang.reflect.Array;
import
java.lang.reflect.Field;
import
java.lang.reflect.InvocationTargetException;
import
java.lang.reflect.Method;
import
java.lang.reflect.Modifier;
import
java.util.Arrays;
public
class
RefInt {
public
static
void
main(String[] args) {
System.
out
.println(
"f_1()"
);
f_1();
System.
out
.println(
"f_2()"
);
f_2();
System.
out
.println(
"f_3()"
);
f_3();
System.
out
.println(
"f_4()"
);
f_4();
System.
out
.println(
"getArrayByIndex()"
);
int
[] a = {10,2,3,5};
String[] s = {
"aabc"
,
"aaabc"
,
"def"
,
"f"
};
//
数组排序
Arrays.sort(s);
System.
out
.println(getArrayByIndex(s,0));
System.
out
.println(getArrayByIndex(a,0));
System.
out
.println(getArrayByIndex(a,3));
Arrays.sort(a);
System.
out
.println(getArrayByIndex(a,0));
System.
out
.println(getArrayByIndex(a,3));
Array.set(a, 0, -1);
System.
out
.println(getArrayByIndex(a,0));
}
/**
*
获得数组
o
下标为
index
的值
*
@param
o
*
@param
index
*
@return
*/
public
static
Object getArrayByIndex(Object o ,
int
index) {
return
Array.get(o, index);
}
/**
*
通过类名得到类描述对象
*
通过类描述对象获得类模式(此类为
public
)
*/
public
static
void
f_4() {
try
{
Class class_my = Class.forName(
"RefInt.Model"
);
int
m = class_my.getModifiers();
System.
out
.println(class_my.getModifiers());
if
(Modifier.isPublic(m))
System.
out
.println(
"public"
);
}
catch
(ClassNotFoundException e) {
e.printStackTrace();
}
catch
(SecurityException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
}
/**
*
通过类名得到类描述对象
*
通过类描述对象获得属性对象列表并显示其属性
*/
public
static
void
f_3() {
try
{
Class class_my = Class.forName(
"RefInt.Model"
);
//
只能得到属性是
public
的
Field
Field[] publicFields = class_my.getFields();
for
(
int
i = 0; i < publicFields.
length
; i++) {
String fieldName = publicFields[i].getName();
Class typeClass = publicFields[i].getType();
String fieldType = typeClass.getName();
System.
out
.println(
"Name: "
+ fieldName +
", Type: "
+ fieldType);
}
}
catch
(ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
*
通过实体对象获得类描述对象
*
通过累描述对象获得指定属性对象
*
通过属性对象实例得到属性名和属性值
*/
public
static
void
f_2() {
Model model =
new
Model();
//
属性必须是
public,
否则抛出
NoSuchFieldException
异常
String sfiled =
"name"
;
Class class_my = model.getClass();
try
{
Field filed = class_my.getField(sfiled);
System.
out
.println(filed.getName());
System.
out
.println(filed.get(model));
}
catch
(SecurityException e) {
e.printStackTrace();
}
catch
(NoSuchFieldException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(IllegalAccessException e) {
e.printStackTrace();
}
}
/**
*
通过类名获得实体对象
*
通过属性名称获取实体对象属性值
*/
public
static
void
f_1() {
try
{
Class cla = Class.forName(
"RefInt.Model"
);
Object o = cla.newInstance();
String methodName =
"getName"
;
Method m = cla.getMethod(methodName, (Class[])
null
);
System.
out
.println(m.invoke(o, (Object[])
null
));
methodName =
"getAge"
;
m = cla.getMethod(methodName, (Class[])
null
);
System.
out
.println(m.invoke(o, (Object[])
null
));
methodName =
"getB"
;
m = cla.getMethod(methodName, (Class[])
null
);
System.
out
.println(m.invoke(o, (Object[])
null
));
}
catch
(ClassNotFoundException e) {
e.printStackTrace();
}
catch
(InstantiationException e) {
e.printStackTrace();
}
catch
(IllegalAccessException e) {
e.printStackTrace();
}
catch
(SecurityException e) {
e.printStackTrace();
}
catch
(NoSuchMethodException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(InvocationTargetException e) {
e.printStackTrace();
}
}
}
一般的做法是通过类
Introspector
来获取某个对象的
BeanInfo
信息,然后通过
BeanInfo
来获取属性的描述器(
PropertyDescriptor
),通过这个属性描述器就可以获取某个属性对应的
getter/setter
方法,然后我们就可以通过反射机制来调用这些方法。
Intro.java
package
RefInt;
import
java.beans.BeanInfo;
import
java.beans.IntrospectionException;
import
java.beans.Introspector;
import
java.beans.PropertyDescriptor;
import
java.lang.reflect.InvocationTargetException;
public
class
Intro {
public
static
void
main(String[] args) {
Model m =
new
Model();
try
{
//
从其所在位置开始停止分析的基类。
stopClass
或其基类中的所有方法
/
属性
/
事件都将在分析中被忽略。
BeanInfo beanInfor = Introspector.getBeanInfo(m.getClass(),Object.
class
);
PropertyDescriptor[] p = beanInfor.getPropertyDescriptors();
for
(
int
i=0;i<p.
length
;i++){
System.
out
.println(p[i].getName()+
"="
+
p[i].getReadMethod().invoke(m,(Object[])
null
));
}
}
catch
(IntrospectionException e) {
e.printStackTrace();
}
catch
(IllegalArgumentException e) {
e.printStackTrace();
}
catch
(IllegalAccessException e) {
e.printStackTrace();
}
catch
(InvocationTargetException e) {
e.printStackTrace();
}
}
}