先貼一些反射的基本知識:
--------------------------------------------------------------------
一、什么是反射:
反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪問、檢測和修改它本身狀態或行為的一種能力。這一概念的提 出很快引發了計算機科學領域關于應用反射性的研究。它首先被程序語言的設計領域所采用,并在Lisp和面向對象方面取得了成績。其中 LEAD/LEAD++ 、OpenC++ 、MetaXa和Openjava等就是基于反射機制的語言。最近,反射機制也被應用到了視窗系統、操作系統和文件系統中。
反射本身并不 是一個新概念,盡管計算機科學賦予了反射概念新的含義。在計算機科學領域,反射是指一類應用,它們能夠自描述和自控制。也就是說,這類應用通過采用某種機 制來實現對自己行為的描述(self-rePResentation)和監測(examination),并能根據自身行為的狀態和結果,調整或修改應用 所描述行為的狀態和相關的語義。
二、什么是Java中的類反射:
Reflection 是 Java 程序開發語言的特征之一,它允許運行中的 Java 程序對自身進行檢查,或者說“自審”,并能直接操作程序的內部屬性和方法。Java 的這一能力在實際應用中用得不是很多,但是在其它的程序設計語言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒有辦法在程序中獲得函數定義相關的信息。
Reflection 是 Java 被視為動態(或準動態)語言的關鍵,允許程序于執行期 Reflection APIs 取得任何已知名稱之 class 的內部信息,包括 package、type parameters、superclass、implemented interfaces、inner classes, outer class, fields、constructors、methods、modifiers,並可于執行期生成instances、變更 fields 內容或喚起 methods。
三、Java類反射中所必須的類:
Java的類反射所需要的類并不多,它們分別是:Field、Constructor、Method、Class、Object,下面我將對這些類做一個簡單的說明。
Field類:提供有關類或接口的屬性的信息,以及對它的動態訪問權限。反射的字段可能是一個類(靜態)屬性或實例屬性,簡單的理解可以把它看成一個封裝反射類的屬性的類。
Constructor類:提供關于類的單個構造方法的信息以及對它的訪問權限。這個類和Field類不同,Field類封裝了反射類的屬性,而Constructor類則封裝了反射類的構造方法。
Method類:提供關于類或接口上單獨某個方法的信息。所反映的方法可能是類方法或實例方法(包括抽象方法)。 這個類不難理解,它是用來封裝反射類方法的一個類。
Class類:類的實例表示正在運行的 Java 應用程序中的類和接口。枚舉是一種類,注釋是一種接口。每個數組屬于被映射為 Class 對象的一個類,所有具有相同元素類型和維數的數組都共享該 Class 對象。
Object類:每個類都使用 Object 作為超類。所有對象(包括數組)都實現這個類的方法。
以上來自 http://www.survivalescaperooms.com/forlina/archive/2011/06/21/2085849.html
--------------------------------------------------------------------
反射的優勢在于它可以在程序運行期間動態地構造對象,比較常見的例子是json格式的字符串轉化成對象,可以找一些源碼參看。
最近寫了個方法,用反射的方式根據xml文件和配置文件構造所需的對象,分享在這里。
public static <T> T createObjectFromXMLAndProperty(Document document, Map<String, String> config, Class<T> clazz)
document:xml文件生成的Document對象,數據源
config:配置信息,標明構造的對象所需的數據在xml中的位置
clazz:目標對象
其中的config配置信息是要自己寫的,也有一定的寫法,例如:
a=xx
b=
c=/root/ele
d=/root/ele[@att]
e=/root/ele;/root/ele[@att]
f=/root/nodes/node[$]
g.aa=/root/nodes/node[$][@key]
g.bb=/root/nodes/node[$][@value]
"="左側是目標對象中的字段名,右側是數據/數據的xpath/多個數據
左側:a:目標對象中的a字段
g.aa:目標對象中的g,中的aa字段
同理,對于對象中不是基本類型的對象,用a.b.c....的形式構造
右側:具體的值
空:默認值
xpath:xpath指向的xml中的節點的value
xpath[@att]:xpath指向的xml中的節點名為“att”的屬性
xpath[$]:取出一系列數據,構造List(僅list可用)
*;*;...:用";"分割的一系列數據構造目標字段(需要有相應的set方法)
以上的寫法可以互相搭配使用。
優點:以后遇到解析xml文件的情況時,只需要編寫一個配置文件即可,迭代速度快,之后若有改動也是改配置文件,代碼不用變動。
不足:只支持構造可以分解為基本類型和List的對象,還有一些類型待添加,如Map等等;
當取數邏輯復雜時,無能為力,比如要取出比a節點的value大的所有節點,好好敲代碼吧——或者取出來再做處理。
代碼如下:
public class XMLAnalysisUtils { private static final String REGEX_RULE = "http://[@(//w+)//]"; private static final Pattern pat = Pattern.compile(REGEX_RULE); private static final Splitter splitter = Splitter.on(";"); private static Map<Type, AbstractStringConverter> typeMap = Maps.newHashMap(); /** * 根據xml和properties構造對象,properties用于描述對象中的字段的值在xml中到位置 * * @param document xml數據 * @param config properties * @param clazz 目標對象 * @return 對象實體 * @throws Exception */ public static <T> T createObjectFromXMLAndProperty(Document document, Map<String, String> config, Class<T> clazz) throws Exception { initTypeMap(); return (T) createObjectFromXMLAndProperty(document, config, clazz, ""); } private static void initTypeMap() { typeMap.put(boolean.class, new BooleanConverter()); typeMap.put(int.class, new IntegerConverter()); typeMap.put(double.class, new DoubleConverter()); typeMap.put(Boolean.class, new BooleanConverter()); typeMap.put(Integer.class, new IntegerConverter()); typeMap.put(Double.class, new DoubleConverter()); typeMap.put(String.class, new StringConverter()); } private static Object createObjectFromXMLAndProperty(Document document, Map<String, String> properties, Class clazz, String owner) throws Exception { Method[] methods = clazz.getDeclaredMethods(); Object object = clazz.newInstance(); for (Method method : methods) { String methodName = method.getName(); Type[] type = method.getGenericParameterTypes(); if (!methodName.startsWith("set")) { continue; } String parameter = owner + methodName.substring(3, 4).toLowerCase() + methodName.substring(4); String xPath = properties.get(parameter); if (xPath != null) { if (xPath.isEmpty()) { if (type.length == 1 && String.class == type[0]) { method.invoke(object, ""); } continue; } if (!isBaseType(type)) { if (type[0] instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) type[0]; Type tp = pt.getActualTypeArguments()[0]; if (!isBaseType(tp)) { continue; } Object results = createList(document, properties, tp, parameter); method.invoke(object, results); } continue; } List<String> values = getValue(document, xPath); if (isAllNull(values)) { continue; } List<Object> result = transType(values, type); if (result == null) { continue; } method.invoke(object, result.toArray()); continue; } if (isBaseType(type)) { if (type.length == 1 && String.class == type[0]) { method.invoke(object, ""); } continue; } if (type[0] instanceof Class) { Object res = createObjectFromXMLAndProperty(document, properties, (Class) type[0], parameter + "."); method.invoke(object, res); continue; } if (type[0] instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) type[0]; if (pt.getRawType().equals(List.class)) { Type tp = pt.getActualTypeArguments()[0]; Object results = createListObjectFromXMLAndProperty(document, properties, (Class) tp, parameter + "."); method.invoke(object, results); } } } return object; } private static Object createListObjectFromXMLAndProperty(Document document, Map<String, String> properties, Class clazz, String owner) throws Exception { Method[] methods = clazz.getDeclaredMethods(); List<Object> objects = Lists.newArrayList(); Integer row = 1; boolean mark = true; boolean isList = true; while (mark & isList) { mark = false; isList = false; Object object = clazz.newInstance(); for (Method method : methods) { String methodName = method.getName(); Type[] type = method.getGenericParameterTypes(); if (!methodName.startsWith("set")) { continue; } String parameter = owner + methodName.substring(3, 4).toLowerCase() + methodName.substring(4); String xPath = properties.get(parameter); if (xPath != null) { if (xPath.isEmpty()) { if (type.length == 1 && String.class == type[0]) { method.invoke(object, ""); } continue; } if (xPath.contains("$")) { isList = true; } if (!isBaseType(type)) { if (type[0] instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) type[0]; Type tp = pt.getActualTypeArguments()[0]; if (!isBaseType(tp)) { continue; } Object results = createList(document, properties, tp, parameter); method.invoke(object, results); } continue; } List<String> values = getValue(document, xPath.replaceAll("http://$", row.toString())); if (isAllNull(values)) { continue; } List<Object> result = transType(values, type); if (result == null) { continue; } mark = mark || xPath.contains("$");//非固定值被invoke時判定為可繼續 method.invoke(object, result.toArray()); continue; } if (isBaseType(type)) { if (type.length == 1 && String.class == type[0]) { method.invoke(object, ""); } continue; } if (type[0] instanceof Class) { logger.debug("type0:{}, method.name{}", type[0].toString(), method.getName()); Object res = createObjectFromXMLAndProperty(document, properties, (Class) type[0], parameter + "."); method.invoke(object, res); continue; } if (type[0] instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) type[0]; if (pt.getRawType().equals(List.class)) { Type tp = pt.getActualTypeArguments()[0]; Object results = createListObjectFromXMLAndProperty(document, properties, (Class) tp, parameter + "."); method.invoke(object, results); } } } objects.add(object); row++; } objects.remove(objects.size() - 1); return objects; } private static Object createList(Document document, Map<String, String> properties, Type type, String parameter) { List<Object> objects = Lists.newArrayList(); Integer row = 1; boolean mark = true; boolean isList = true; while (mark & isList) { mark = false; String xPath = properties.get(parameter); if (xPath == null) { return null; } if (xPath.isEmpty()) { return objects; } if (!xPath.contains("$")) { isList = false; } xPath = xPath.replaceAll("http://$", row.toString()); List<String> values = getValue(document, xPath); if (isAllNull(values)) { continue; } List<Object> result = transType(values, type); if (result == null) { continue; } mark = true; objects.add(result.get(0)); row++; } return objects; } private static List<Object> transType(List<String> values, Type... types) { if (values.size() != types.length) { return null; } List<Object> result = Lists.newArrayList(); int len = values.size(); for (int i = 0; i < len; i++) { result.add(typeMap.get(types[i]).doForward(values.get(i))); } return result; } private static List<String> getValue(Document document, String xPath) { List<String> paths = splitter.splitToList(xPath); List<String> values = Lists.newArrayList(); for (String path : paths) { if (!path.startsWith("/")) { values.add(path); continue; } Element element; element = (Element) document.selectSingleNode(path); if (element == null) { values.add(null); continue; } if (path.contains("@")) { Matcher match = pat.matcher(path); if (match.find()) { String attr = match.group(1); values.add(element.attributeValue(attr)); } continue; } values.add(element.getStringValue()); } return values; } private static boolean isBaseType(Type... types) { return typeMap.keySet().containsAll(Lists.newArrayList(types)); } private static boolean isAllNull(List<String> values) { boolean result = true; if (values == null) { return true; } for (String value : values) { result = result && value == null; } return result; }}
新聞熱點
疑難解答