Java反射-1(理論)
Java反射-2(技巧)
JAVA反射-3(性能)
什么叫做反射?反射有什么用怎炊?這篇文章會(huì)娓娓道來(lái)壁肋。
咱們就先從反射官網(wǎng)入手,開(kāi)始解讀下吧印荔。
1. 官網(wǎng)解讀:
1.1 什么叫做反射
Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine.
反射通常是被程序使用惜辑,這些程序需要能夠檢查或修改運(yùn)行在JVM的應(yīng)用程序的運(yùn)行時(shí)行為优俘。
1.1.1 反射的優(yōu)點(diǎn)
Extensibility Features
An application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified names.
可擴(kuò)展功能
應(yīng)用程序可使用 完全限定的名稱 創(chuàng)建 可擴(kuò)展對(duì)象的實(shí)例 來(lái)使用外部或用戶定義的類(lèi)。
1.1.2 反射的缺點(diǎn)
Performance Overhead
Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
性能開(kāi)銷(xiāo)
由于反射設(shè)計(jì)到動(dòng)態(tài)解析的類(lèi)型,因此無(wú)法執(zhí)行某些JVM的優(yōu)化籍琳。因此先舷,反射操作性能低于非反射操作,應(yīng)該避免在性能敏感的程序中頻繁調(diào)用前方。
Exposure of Internals
Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform.
內(nèi)部暴露
由于反射允許代碼執(zhí)行非法的操作在非反射代碼中狈醉,例如,訪問(wèn)私有字段或方法惠险,因此使用反射可能導(dǎo)致意外的副作用苗傅,可能導(dǎo)致代碼功能失常并可能失去可移植性,反射代碼打破了抽象莺匠,因此使用反射的代碼可能會(huì)在系統(tǒng)升級(jí)后表現(xiàn)異常金吗。
Security Restrictions
Reflection requires a runtime permission which may not be present when running under a security manager. This is in an important consideration for code which has to run in a restricted security context, such as in an Applet.
安全限制
反射需要運(yùn)行時(shí)的權(quán)限,因此無(wú)法在安全管理器下運(yùn)行,必須受限于安全的上下文中運(yùn)行摇庙,例如Applet旱物,只是一個(gè)重要的考慮因素。
1.2 Class對(duì)象的學(xué)習(xí)
Every type is either a reference or a primitive.
每一種對(duì)象都是引用類(lèi)型或者基本數(shù)據(jù)類(lèi)型卫袒。
For every type of object, the Java virtual machine instantiates an immutable instance of
java.lang.Class
which provides methods to examine the runtime properties of the object including its members and type information.Class
also provides the ability to create new classes and objects. Most importantly, it is the entry point for all of the Reflection APIs.
對(duì)于每一種對(duì)象的類(lèi)型宵呛,JVM提供了一個(gè)不可變對(duì)象,java.lang.Class
不可變對(duì)象提供了檢查運(yùn)行時(shí)對(duì)象 成員和類(lèi)型信息的方法夕凝。還提供了創(chuàng)建類(lèi)和對(duì)象的功能宝穗。最重要的,他是反射API的入口點(diǎn)码秉。
1.2.1 getClass()語(yǔ)法
If an instance of an object is available, then the simplest way to get its
Class
is to invokeObject.getClass()
. Of course, this only works for reference types which all inherit fromObject
.
對(duì)象是可用的情況:得到它的class
對(duì)象最簡(jiǎn)單的方法就是object.getClass()
逮矛,當(dāng)然,這僅僅適用于繼承與object
下的類(lèi)转砖。
public static void main(String[] args) {
Heap heap = new Heap();
System.out.println("普通對(duì)象的返回類(lèi)型:" + heap.getClass());
//注意须鼎,聲明類(lèi)型 xx=new 實(shí)際類(lèi)型();返回的是實(shí)際類(lèi)型
Set set = new HashSet();
System.out.println("實(shí)際類(lèi)型的返回類(lèi)型:" + set.getClass());
//注意數(shù)據(jù)的返回類(lèi)型
byte[] bytes = new byte[1024];
System.out.println("數(shù)組的返回類(lèi)型:" + bytes.getClass());
System.out.println("枚舉的返回類(lèi)型:"+enums.RED.getClass());
}
執(zhí)行結(jié)果:
1.2.2 .class語(yǔ)法
If the type is available but there is no instance then it is possible to obtain a Class
by appending ".class"
to the name of the type.
如果類(lèi)型可用但沒(méi)有對(duì)象:可以通過(guò)Class
附帶的".class"
名稱獲取Class
對(duì)象。
1.2.3 Class.forName()語(yǔ)法
If the fully-qualified name of a class is available, it is possible to get the corresponding Class
using the static method Class.forName()
. This cannot be used for primitive types.
一個(gè)類(lèi)的完全限定名可用:可以使用靜態(tài)方法Class.forName()
去創(chuàng)建Class
對(duì)象府蔗,不能用于基本數(shù)據(jù)類(lèi)型晋控。
1.2.4 Type用法
The
.class
syntax is a more convenient and the preferred way to obtain theClass
for a primitive type; however there is another way to acquire theClass
. Each of the primitive types andvoid
has a wrapper class injava.lang
that is used for boxing of primitive types to reference types. Each wrapper class contains a field namedTYPE
which is equal to theClass
for the primitive type being wrapped.
對(duì)于基本數(shù)據(jù)類(lèi)型,.class
方式是一種便捷的姓赤、首選的方式來(lái)獲取Class
對(duì)象赡译。然而有另一種方法去創(chuàng)建Class
對(duì)象。每一種基本數(shù)據(jù)類(lèi)型和void
都有一個(gè)包裝類(lèi)java.lang
不铆。用于將基本數(shù)據(jù)類(lèi)型裝箱蝌焚。每一個(gè)包裝類(lèi)包含一個(gè)TYPE
的域,該字段等于Class
被包裝的基本類(lèi)型狂男。
對(duì)于非基本數(shù)據(jù)類(lèi)型综看,返回的是編譯錯(cuò)誤。
測(cè)試代碼:
public static void main(String[] args) {
Class dobClass = Double.TYPE;
//Void也有封裝類(lèi)型岖食!
Class voidClass=Void.TYPE;
System.out.println(dobClass);
System.out.println(voidClass);
}
輸出結(jié)果:
1.2.5 返回Class的方法
There are several Reflection APIs which return classes but these may only be accessed if a
Class
has already been obtained either directly or indirectly.
有幾個(gè)Reflection API
可以返回classes
對(duì)象红碑,但只有Class
對(duì)象直接或者間接獲取的情況下。
下面getclasses()
知識(shí)點(diǎn)需要用到成員內(nèi)部類(lèi)泡垃,可以先了解下析珊。
public static void main(String[] args) {
//返回作為類(lèi)成員的所有公共類(lèi),接口和枚舉蔑穴,包括繼承的成員忠寻。
Class<?>[] dobClass = HashMap.class.getClasses();
for (Class c : dobClass) {
System.out.println("類(lèi)或其父類(lèi)所有成員public內(nèi)部類(lèi):" + c);
}
Class<?>[] declaredClasses = HashMap.class.getDeclaredClasses();
for (Class c1 : declaredClasses) {
System.out.println("本類(lèi)所有成員內(nèi)部類(lèi):"+c1);
}
}
執(zhí)行結(jié)果:
下面這個(gè)類(lèi)實(shí)現(xiàn)了:獲取類(lèi)的聲明組件,包括修飾符存和,泛型類(lèi)型參數(shù)奕剃,實(shí)現(xiàn)的接口和繼承路徑衷旅。由于 Class
實(shí)現(xiàn)了java.lang.reflect.AnnotatedElement
接口,因此還可以查詢運(yùn)行時(shí)注釋纵朋。
public class Reflect {
public static void main(String[] args) {
try {
Class<?> c = Class.forName("Algorithm.Outer");
out.println("Class:" + c.getCanonicalName());
out.println("訪問(wèn)修飾符:" + Modifier.toString(c.getModifiers()));
TypeVariable<? extends Class<?>>[] tv = c.getTypeParameters();
if (tv.length != 0) {
for (TypeVariable t : tv) {
out.println("泛型類(lèi)型:" + t.getName());
}
out.println();
} else {
out.println("--無(wú)泛型的參數(shù)類(lèi)型--");
}
//獲取接口類(lèi)型
Type[] intfs = c.getGenericInterfaces();
if (intfs.length != 0) {
for (Type intf : intfs)
out.println("接口類(lèi)型:" + intf.toString());
} else {
out.format("--無(wú)接口類(lèi)型--");
}
//將父類(lèi)保存到List集合里面
List<Class> l = new ArrayList<Class>();
printAncestor(c, l);
if (l.size() != 0) {
for (Class<?> cl : l)
//打印父類(lèi)名稱
out.println("父類(lèi)名稱:" + cl.getCanonicalName());
} else {
out.format("--沒(méi)有父類(lèi)名稱--");
}
Annotation[] ann = c.getAnnotations();
if (ann.length != 0) {
for (Annotation a : ann)
out.println("注釋信息:" + a.toString());
} else {
out.format(" --沒(méi)有注釋信息--");
}
// production code should handle this exception more gracefully
} catch (ClassNotFoundException x) {
x.printStackTrace();
}
}
//遞歸方法柿顶,返回所以的父類(lèi)類(lèi)型,直至Object類(lèi)
private static void printAncestor(Class<?> c, List<Class> l) {
Class<?> ancestor = c.getSuperclass();
if (ancestor != null) {
l.add(ancestor);
printAncestor(ancestor, l);
}
}
}
Since arrays are runtime objects, all of the type information is defined by the Java virtual machine. In particular, arrays implement
Cloneable
andjava.io.Serializable
and their direct superclass is alwaysObject
.
由于數(shù)組是運(yùn)行時(shí)對(duì)象操软,因此所有的類(lèi)型信息都由JVM定義的嘁锯。特別是,數(shù)組實(shí)現(xiàn)Clonable
和java.io.Serializable
聂薪,他的直接超類(lèi)總是Object
家乘;
2. 源碼實(shí)現(xiàn)
將XML數(shù)據(jù)轉(zhuǎn)化為Object對(duì)象,將Object對(duì)象轉(zhuǎn)化為XML文件藏澳。
/**
* XML轉(zhuǎn)化為Object
*
* @throws IllegalAccessException
* @throws InstantiationException
*/
public final static void objectFromXml(Object obj, String xml) throws InstantiationException,
IllegalAccessException {
Element root = parseXml(xml);
Class clazz = obj.getClass();
do
objectFromXml(obj, clazz, root);
while ((clazz = clazz.getSuperclass()) != null);
}
public final static void objectFromXml(Object obj, Class clazz, Element root)
throws InstantiationException, IllegalAccessException {
if (root == null || (root.elements()).size() == 0) {
return;
}
// 獲取私有變量
Field[] fields = clazz.getDeclaredFields();
// 暴力解除
Field.setAccessible(fields, true);
for (Field field : fields) {
// field.getModififers()獲取
String name = field.getName();
Class type = field.getType();
// 內(nèi)省機(jī)制仁锯,證明該字段在此對(duì)象里面是可編輯的
if ((!Modifier.isStatic(field.getModifiers())) && PropertyUtils.isWriteable(obj, name)) {
// 獲取屬性的類(lèi)型
// 判斷類(lèi)型來(lái)自哪里(可指定的)
if (type.isAssignableFrom(List.class)) {
// 獲取屬性的Type類(lèi)型
Type genericType = field.getGenericType();
List<Element> elements = root.elements(name);
// 根本沒(méi)有這個(gè)節(jié)點(diǎn)的話,那么不予賦值
if ((elements == null) && elements.size() == 0) {
continue;
}
// 判斷該Type類(lèi)型是不是參數(shù)化的文件
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
Class parameterizedClass = (Class) pt.getActualTypeArguments()[0];
// 想當(dāng)與new了一個(gè)對(duì)象
List lists = new ArrayList();
for (Element ele : elements) {
Object object = parameterizedClass.newInstance();
// 判斷泛型是否是基本數(shù)據(jù)對(duì)象
if (isPrimitiveType(parameterizedClass)) {
// 將element里面的對(duì)象賦值到反射出的對(duì)象里面
object = setObjectValue(object, ele.getText());
} else {
// 迭代笆载,無(wú)論執(zhí)行都少次扑馁,最后一次,將正確的值返回
objectFromXml(object, parameterizedClass, ele);
}
lists.add(object);
}
// 將obj對(duì)象的List集合賦值
field.set(obj, lists);
}
} else {
// 若不包含改節(jié)點(diǎn)
String text = root.elementText(name);
if (null != text) {
try {
if (isPrimitiveType(field.getType())) {
setObjectValue(obj, field, text);
} else {
// 創(chuàng)建改屬性的object凉驻、class、節(jié)點(diǎn)
Object fieldObject = type.newInstance();
Element fieldRoot = root.element(name);
objectFromXml(fieldObject, type, fieldRoot);
// 為obj對(duì)象里面的field屬性賦予fieldObject對(duì)象的值
field.set(obj, fieldObject);
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
Object轉(zhuǎn)化為XML:
public static void ObjectToXML(Object obj, Element root) throws IllegalArgumentException,
IllegalAccessException, SecurityException, NoSuchMethodException,
InvocationTargetException, ParseException {
// 創(chuàng)建Class對(duì)象
Class clazz = obj.getClass();
do
ObjectToXML(obj, clazz, root);
while ((clazz = clazz.getSuperclass()) != null);
}
public static void ObjectToXML(Object obj, Class clazz, Element root)
throws IllegalArgumentException, IllegalAccessException, SecurityException,
NoSuchMethodException, InvocationTargetException, ParseException {
Field[] fields = clazz.getDeclaredFields();
Field.setAccessible(fields, true);
for (Field field : fields) {
// 判斷是否是List
Class fieldClass = field.getType();
String name = field.getName();
Object descObj = field.get(obj);
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
if (descObj == null) {
if (isPrimitiveType(fieldClass)) {
descObj = "";
} else {
continue;
}
}
if (fieldClass.isAssignableFrom(List.class)) {
Type genType = field.getGenericType();
if (genType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genType;
Class paramClass = (Class) pt.getActualTypeArguments()[0];
System.out.println("List的泛型對(duì)象:" + paramClass);
String paramText = null;
// 判斷參數(shù)的類(lèi)型
List paramList = (ArrayList) descObj;
// foreach循環(huán)前需要加判斷
if (paramList == null || paramList.size() == 0 || paramClass == null) {
continue;
}
Method m = fieldClass.getDeclaredMethod("size", new Class[0]);
Integer size = (Integer) m.invoke(descObj, new Object[0]);
root.addElement(name + "_NUM").setText(size + "");
Element childEle = null;
// 獲取list集合里面的對(duì)象
for (Object object : paramList) {
if (isPrimitiveType(paramClass)) {
childEle = root.addElement(name);
root.addText(String.valueOf(getObjectValue(object, paramClass)));
} else {
childEle = new DOMElement(name);
ObjectToXML(object, childEle);
root.add(childEle);
}
}
}
} else if (fieldClass.isAssignableFrom(Map.class)) {
Map map = (Map) descObj;
Type mapGentype = field.getGenericType();
// 若是泛型類(lèi)型
if (mapGentype instanceof ParameterizedType) {
ParameterizedType mapPt = (ParameterizedType) mapGentype;
Class keyClass = (Class) mapPt.getActualTypeArguments()[0];
Type valueType = mapPt.getActualTypeArguments()[1];
Class valueClass = (Class) valueType;
Iterator<Map.Entry> it = map.entrySet().iterator();
// 默認(rèn)Key是基本類(lèi)型
while (it.hasNext()) {
Entry entry = it.next();
Object keyObject = entry.getKey();
System.out.println("map的key:" + keyObject);
Object valueObject = entry.getValue();
System.out.println("map的value:" + valueObject.getClass());
Element mapEle = null;
// 設(shè)置到XML里面
String keyName = null;
if (isPrimitiveType(keyClass)) {
keyName = (String) getObjectValue(keyObject, keyClass);
} else {
continue;
}
if (isPrimitiveType(valueClass)) {
mapEle = root.addElement(keyName); // 創(chuàng)建節(jié)點(diǎn)
mapEle.setText((String) getObjectValue(valueObject, valueClass));
} else {
// 若是對(duì)象
mapEle = new DOMElement(keyName);
Element childEle = null;
if (valueObject instanceof List) {
// 若是list集合复罐,直接繼續(xù)賦值
List mapList = (ArrayList) valueObject;
if (mapList == null || map.size() == 0) {
continue;
}
Class cls = mapList.get(0).getClass(); // 獲取List對(duì)象的泛型的對(duì)象類(lèi)型
for (Object object : mapList) {
if (isPrimitiveType(cls)) {
childEle = root.addElement(name);
mapEle.addText(String.valueOf(getObjectValue(object, cls)));
} else {
childEle = new DOMElement(name);
ObjectToXML(object, childEle);
mapEle.add(childEle);
}
}
} else {
ObjectToXML(valueObject, mapEle);
}
root.add(mapEle);
}
}
}
} else {
// 屬性字段是否是普通對(duì)象普通對(duì)象
Element childEle = new DOMElement(name);
if (isPrimitiveType(fieldClass)) {
childEle.setText(String.valueOf(getObjectValue(descObj, fieldClass)));
} else {
ObjectToXML(descObj, childEle);
}
root.add(childEle);
}
}
}
工具類(lèi):
/**
* 解析Element節(jié)點(diǎn)
*
* @param xml
* @return
*/
private static Element parseXml(String xml) {
Element root = null;
try {
Document doc = DocumentHelper.parseText(xml);
root = doc.getRootElement();
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return root;
}
/**
*
* @param object
* 目標(biāo)對(duì)象
* @param field
* 目標(biāo)對(duì)象的反射字段
* @param text
* 需要反射字段賦予的值
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws NumberFormatException
* @throws ParseException
*/
private static void setObjectValue(Object object, Field field, String text)
throws NumberFormatException, IllegalArgumentException, IllegalAccessException,
ParseException {
if (object == null || field == null) {
return;
}
// 獲取反射字段的Class對(duì)象涝登。getClass()返回的是Field對(duì)象
Class fieldClass = field.getType();
if (fieldClass.isAssignableFrom(long.class) || fieldClass.isAssignableFrom(Long.class)) {
field.set(object, Long.valueOf(text));
} else if (fieldClass.isAssignableFrom(int.class)
|| fieldClass.isAssignableFrom(Integer.class)) {
field.set(object, Integer.valueOf(text));
} else if (fieldClass.isAssignableFrom(double.class)
|| fieldClass.isAssignableFrom(Double.class)) {
field.set(object, Double.valueOf(text));
} else if (fieldClass.isAssignableFrom(float.class)
|| fieldClass.isAssignableFrom(Float.class)) {
field.set(object, Float.valueOf(text));
} else if (fieldClass.isAssignableFrom(boolean.class)
|| fieldClass.isAssignableFrom(Boolean.class)) {
field.set(object, Boolean.valueOf(text));
} else if (fieldClass.isAssignableFrom(Date.class)) {
DateFormat df = new SimpleDateFormat("yyyyMMddhhmmss");
field.set(object, df.parse(text));
} else if (fieldClass.isAssignableFrom(String.class)) {
field.set(object, text);
} else if (fieldClass.isArray()) {
field.set(object, text.toCharArray());
} else {
field.set(object, text);
}
}
private static Object getObjectValue(Object object, Class paramsClass)
throws IllegalArgumentException, IllegalAccessException, ParseException {
if (object == null) {
return null;
}
if (paramsClass.isAssignableFrom(Date.class)) {
DateFormat dt = new SimpleDateFormat("yyyyMMddhhmmss");
object = dt.format(object);
} else if (paramsClass.isAssignableFrom(Double.class)
|| paramsClass.isAssignableFrom(double.class)) {
// double類(lèi)型格式化
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(8);
object = nf.format((Double) object);
} else {
object = String.valueOf(object);
}
return object;
}
// 返回泛型(反射的new)對(duì)象的值 。
private static Object setObjectValue(Object object, String text) {
if (object == null)
return null;
Class clazz = object.getClass();
if (clazz.isAssignableFrom(long.class) || clazz.isAssignableFrom(Long.class)) {
object = Long.valueOf(text);
} else if (clazz.isAssignableFrom(int.class) || clazz.isAssignableFrom(Integer.class)) {
object = Integer.valueOf(text);
} else if (clazz.isAssignableFrom(double.class) || clazz.isAssignableFrom(Double.class)) {
object = Double.valueOf(text);
} else if (clazz.isAssignableFrom(float.class) || clazz.isAssignableFrom(Float.class)) {
object = Float.valueOf(text);
} else if (clazz.isAssignableFrom(boolean.class) || clazz.isAssignableFrom(Boolean.class)) {
object = Boolean.valueOf(text);
} else if (clazz.isAssignableFrom(Date.class)) {
DateFormat df = new SimpleDateFormat("yyyymmddhhmiss");
try {
object = df.parse(text);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
object = text;
}
return object;
}
// 將其超類(lèi)刪除
private static boolean isPrimitiveType(Class<?> clazz) {
boolean isPrimitiveOrPrimitiveClass = Boolean.valueOf(false);
if ((!clazz.isAssignableFrom(Object.class))
&& ((clazz.isPrimitive() || clazz.isAssignableFrom(Double.class)
|| clazz.isAssignableFrom(Float.class)
|| clazz.isAssignableFrom(Long.class)
|| clazz.isAssignableFrom(Integer.class)
|| clazz.isAssignableFrom(Boolean.class)
|| clazz.isAssignableFrom(Byte.class)
|| clazz.isAssignableFrom(Character.class)
|| clazz.isAssignableFrom(Short.class)
|| clazz.isAssignableFrom(String.class) || clazz
.isAssignableFrom(Date.class)))) {
isPrimitiveOrPrimitiveClass = Boolean.valueOf(true);
}
return isPrimitiveOrPrimitiveClass;
}