色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁技術(shù)文章
文章詳情頁

一文搞懂Java中的反射機(jī)制

瀏覽:106日期:2022-08-26 17:15:59

前一段時(shí)間一直忙,所以沒什么時(shí)間寫博客,拖了這么久,也該更新更新了。最近看到各種知識付費(fèi)的推出,感覺是好事,也是壞事,好事是對知識沉淀的認(rèn)可與推動(dòng),壞事是感覺很多人忙于把自己的知識變現(xiàn),相對的在沉淀上做的實(shí)際還不夠,我對此暫時(shí)還沒有什么想法,總覺得,慢慢來,會(huì)更快一點(diǎn),自己掌握好節(jié)奏就好。

好了,言歸正傳。

反射機(jī)制是Java中的一個(gè)很強(qiáng)大的特性,可以在運(yùn)行時(shí)獲取類的信息,比如說類的父類,接口,全部方法名及參數(shù),全部常量和變量,可以說類在反射面前已經(jīng)衣不遮體了(咳咳,這是正規(guī)車)。先舉一個(gè)小栗子,大家隨意感受一下:

public void testA(){ String name = 'java.lang.String'; try{ Class cl = Class.forName(name); Class supercl = cl.getSuperclass(); String modifiers = Modifier.toString(cl.getModifiers()); if (modifiers.length() > 0){System.out.print(modifiers + ' '); } System.out.print(name); if (supercl != null && supercl != Object.class){System.out.print(' extents ' + supercl.getName()); } System.out.print('{n'); printFields(cl); System.out.println(); printConstructors(cl); System.out.println(); printMethods(cl); System.out.println('}'); }catch (ClassNotFoundException e){ e.printStackTrace(); } System.exit(0); }

private static void printConstructors(Class cl){ Constructor[] constructors = cl.getDeclaredConstructors();for (Constructor c : constructors){ String name = c.getName(); System.out.print(' '); String modifiers = Modifier.toString(c.getModifiers()); if (modifiers.length() > 0){System.out.print(modifiers + ' '); } System.out.print(name + '('); Class[] paraTypes = c.getParameterTypes(); for (int j = 0; j < paraTypes.length; j++){if (j > 0){ System.out.print(', ');}System.out.print(paraTypes[j].getSimpleName()); } System.out.println(');'); } } private static void printMethods(Class cl){ Method[] methods = cl.getDeclaredMethods(); for (Method m : methods){ Class retType = m.getReturnType(); String name = m.getName(); System.out.print(' '); String modifiers = Modifier.toString(m.getModifiers()); if (modifiers.length() > 0){System.out.print(modifiers + ' '); } System.out.print(retType.getSimpleName() + ' ' + name +'('); Class[] paramTypes = m.getParameterTypes(); for(int j = 0; j < paramTypes.length; j++){if (j > 0){ System.out.print(', ');}System.out.print(paramTypes[j].getName()); } System.out.println(');'); } } private static void printFields(Class cl){ Field[] fields = cl.getFields(); for (Field f : fields){ Class type = f.getType(); String name = f.getName(); System.out.print(' '); String modifiers = Modifier.toString(f.getModifiers()); if (modifiers.length() > 0){System.out.print(modifiers + ' '); } System.out.println(type.getSimpleName() + ' ' + name +';'); } }

調(diào)用testA方法輸出如下:

public final java.lang.String{ public static final Comparator CASE_INSENSITIVE_ORDER; public java.lang.String(byte[], int, int); public java.lang.String(byte[], Charset); public java.lang.String(byte[], String); public java.lang.String(byte[], int, int, Charset); public java.lang.String(byte[], int, int, String); java.lang.String(char[], boolean); public java.lang.String(StringBuilder); public java.lang.String(StringBuffer); public java.lang.String(byte[]); public java.lang.String(int[], int, int); public java.lang.String(); public java.lang.String(char[]); public java.lang.String(String); public java.lang.String(char[], int, int); public java.lang.String(byte[], int); public java.lang.String(byte[], int, int, int); public boolean equals(java.lang.Object); public String toString(); public int hashCode(); public int compareTo(java.lang.String); public volatile int compareTo(java.lang.Object); public int indexOf(java.lang.String, int); public int indexOf(java.lang.String); public int indexOf(int, int); public int indexOf(int); static int indexOf([C, int, int, [C, int, int, int); static int indexOf([C, int, int, java.lang.String, int); public static String valueOf(int); public static String valueOf(long); public static String valueOf(float); public static String valueOf(boolean); public static String valueOf([C); public static String valueOf([C, int, int); public static String valueOf(java.lang.Object); public static String valueOf(char); public static String valueOf(double); public char charAt(int); private static void checkBounds([B, int, int); public int codePointAt(int); public int codePointBefore(int); public int codePointCount(int, int); public int compareToIgnoreCase(java.lang.String); public String concat(java.lang.String); public boolean contains(java.lang.CharSequence); public boolean contentEquals(java.lang.CharSequence); public boolean contentEquals(java.lang.StringBuffer); public static String copyValueOf([C); public static String copyValueOf([C, int, int); public boolean endsWith(java.lang.String); public boolean equalsIgnoreCase(java.lang.String); public static transient String format(java.util.Locale, java.lang.String, [Ljava.lang.Object;); public static transient String format(java.lang.String, [Ljava.lang.Object;); public void getBytes(int, int, [B, int); public byte[] getBytes(java.nio.charset.Charset); public byte[] getBytes(java.lang.String); public byte[] getBytes(); public void getChars(int, int, [C, int); void getChars([C, int); private int indexOfSupplementary(int, int); public native String intern(); public boolean isEmpty(); public static transient String join(java.lang.CharSequence, [Ljava.lang.CharSequence;); public static String join(java.lang.CharSequence, java.lang.Iterable); public int lastIndexOf(int); public int lastIndexOf(java.lang.String); static int lastIndexOf([C, int, int, java.lang.String, int); public int lastIndexOf(java.lang.String, int); public int lastIndexOf(int, int); static int lastIndexOf([C, int, int, [C, int, int, int); private int lastIndexOfSupplementary(int, int); public int length(); public boolean matches(java.lang.String); private boolean nonSyncContentEquals(java.lang.AbstractStringBuilder); public int offsetByCodePoints(int, int); public boolean regionMatches(int, java.lang.String, int, int); public boolean regionMatches(boolean, int, java.lang.String, int, int); public String replace(char, char); public String replace(java.lang.CharSequence, java.lang.CharSequence); public String replaceAll(java.lang.String, java.lang.String); public String replaceFirst(java.lang.String, java.lang.String); public String[] split(java.lang.String); public String[] split(java.lang.String, int); public boolean startsWith(java.lang.String, int); public boolean startsWith(java.lang.String); public CharSequence subSequence(int, int); public String substring(int); public String substring(int, int); public char[] toCharArray(); public String toLowerCase(java.util.Locale); public String toLowerCase(); public String toUpperCase(); public String toUpperCase(java.util.Locale); public String trim();}

這里把String類型的所有方法和變量都獲取到了,使用的僅僅是String類型的全名。當(dāng)然,反射的功能不僅僅是獲取類的信息,還可以在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建對象,回想一下,我們正常的對象使用,都是需要在代碼中先聲明,然后才能使用它,但是使用反射后,就能在運(yùn)行期間動(dòng)態(tài)創(chuàng)建對象并調(diào)用其中的方法,甚至還能直接查看類的私有成員變量,還能獲取類的注解信息,在泛型中類型判斷時(shí)也經(jīng)常會(huì)用到。反射可以說完全打破了類的封裝性,把類的信息全部暴露了出來。

上面的代碼看不太明白也沒關(guān)系,只要稍微感受一下反射的能力就好了。介紹完了反射能做的事情,本篇教程就不再寫一些玩具代碼了,這次以一個(gè)實(shí)用型的代碼為媒介來介紹反射。

在開發(fā)中,經(jīng)常會(huì)遇到兩個(gè)不同類對象之間的復(fù)制,把一個(gè)類中的字段信息get取出來,然后set到另一個(gè)類中,大部分情況下,兩個(gè)類對應(yīng)的字段是一樣,每次這樣使用是很麻煩的,那么利用反射就可以實(shí)現(xiàn)一個(gè)封裝,只需要調(diào)用一個(gè)方法即可實(shí)現(xiàn)簡單的類字段復(fù)制。

那么,先來想想,要復(fù)制一個(gè)類對象的所有字段信息到另一個(gè)類對象中,首先,怎么獲取一個(gè)類的某個(gè)字段的值呢?我們先來編寫一個(gè)方法:

/** * 獲取對象的指定字段的值 * @param obj 目標(biāo)對象 * @param fieldName 目標(biāo)字段 * @return 返回字段值 * @throws Exception 可能拋出異常 */ private static Object getFieldValue(Object obj, String fieldName) throws Exception{ //獲取類型信息 Class clazz = obj.getClass(); //取對應(yīng)的字段信息 Field field = clazz.getDeclaredField(fieldName); //設(shè)置可訪問權(quán)限 field.setAccessible(true); //取字段值 Object value = field.get(obj); return value; }

這里使用了兩個(gè)之前沒有說過的類,一個(gè)是Class,是不是很眼熟,想一想,我們每次定義一個(gè)類的時(shí)候是不是都要用到它,哈哈,那你就想錯(cuò)了,那是class關(guān)鍵詞,java是大小寫的敏感的,這里的Class是一個(gè)類名,那這個(gè)類是干嘛用的呢?

虛擬機(jī)在加載每一個(gè)類的時(shí)候,會(huì)自動(dòng)生成一個(gè)對應(yīng)的Class類來保存該類的信息,可以理解為Class類是那個(gè)類的代理類,是連接實(shí)際類與類加載器的橋梁,可以通過它來獲取虛擬機(jī)的類加載器引用,從而實(shí)現(xiàn)更多的騷操作。Class類是一個(gè)泛型類,每個(gè)類都有對應(yīng)的一個(gè)Class類,比如String對應(yīng)的Class類就是Class<String>。

Class有很多方法來獲取更多關(guān)于類的信息,這里使用getDeclaredField方法來獲取指定字段信息,返回的是Field類型對象,這個(gè)對象里存儲著關(guān)于字段的一些信息,如字段名稱,字段類型,字段修飾符,字段可訪問性等,setAccessible方法可以設(shè)置字段的可訪問性質(zhì),這樣就能直接訪問private修飾的字段了,然后使用get方法來獲取指定對象的對應(yīng)字段的值。

我們來測試一下:

public void testB(){ try{ Employee employee = new Employee(); employee.setName('Frank'); employee.setSalary(6666.66); System.out.println((String)getFieldValue(employee,'name')); System.out.println((double)getFieldValue(employee,'salary')); }catch (Exception e){ e.printStackTrace(); } }

輸出如下:

Frank6666.66

接下來,我們需要獲取類中所有字段,然后在另一個(gè)類中查找是否有對應(yīng)字段,如果有的話就設(shè)置字段的值到相應(yīng)的字段中。

/** * 復(fù)制一個(gè)類對象屬性到另一個(gè)類對象中 * @param objA 需要復(fù)制的對象 * @param objB 復(fù)制到的目標(biāo)對象類型 * @return 返回復(fù)制后的目標(biāo)對象 */ private static void parseObj(Object objA,Object objB) throws Exception{ if (objA == null){ return; } //獲取objA的類信息 Class classA = objA.getClass(); Class classB = objB.getClass(); try { //獲取objA的所有字段 Field[] fieldsA = classA.getDeclaredFields(); //獲取objB的所有字段 Field[] fieldsB = classB.getDeclaredFields(); if (fieldsA == null || fieldsA.length <= 0 || fieldsB == null || fieldsB.length <= 0){return; } //生成查詢map Map<String,Field> fieldMap = new HashMap<>(); for (Field field:fieldsA){fieldMap.put(field.getName(),field); } //開始復(fù)制字段信息 for (Field fieldB : fieldsB){//查找是否在objB的字段中存在該字段Field fielaA = fieldMap.get(fieldB.getName());if (fielaA != null){ fieldB.setAccessible(true); fieldB.set(objB,getFieldValue(objA,fielaA.getName()));} } } catch (IllegalStateException e) { throw new IllegalStateException('instace fail: ' ,e); } }

這里獲取到classA和classB的所有字段之后,先生成了一個(gè)map用于查找,可以減少遍歷次數(shù),然后之后只需要遍歷一次就可以判斷相應(yīng)字段是否存在,如果存在則取出對應(yīng)值設(shè)置到相應(yīng)的字段里去。

接下來測試一下:

public void testB(){ try{ //生成Employee對象 Employee employee = new Employee('Frank',6666.66); //生成一個(gè)Manager對象 Manager manager = new Manager(); //復(fù)制對象 parseObj(employee,manager); System.out.println(manager.getName()); System.out.println(manager.getSalary()); }catch (Exception e){ e.printStackTrace(); } }

public class Employee { private String name; private Double salary; public Employee(String name, Double salary) { this.name = name; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; }}

public class Manager { private String name; private Double salary; private Double bonus; public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Double getBonus() { return bonus; } public void setBonus(Double bonus) { this.bonus = bonus; }}

輸出如下:

Frank6666.66

完美,這樣我們就利用了反射機(jī)制完美的把相同的字段在不同類的對象之間進(jìn)行了復(fù)制,這里僅僅是兩個(gè)字段,所以可能好處不明顯,但事實(shí)上,實(shí)際開發(fā)中,經(jīng)常會(huì)有將BO轉(zhuǎn)換為VO的操作,這時(shí)候,這個(gè)操作就很有必要了,簡單的一行命令就可以代替一大堆的get和set操作。

當(dāng)然,使用反射機(jī)制固然高端大氣上檔次,但是也是一把雙刃劍,使用不當(dāng)很可能會(huì)帶來嚴(yán)重后果,而且使用反射的話,會(huì)占用更多資源,運(yùn)行效率也會(huì)降低,上述工具類是用運(yùn)行效率換開發(fā)效率。開發(fā)中不建議大量使用,還是那句話,技術(shù)只是手段,需要使用的時(shí)候再使用,不要為了使用而使用。

至于反射中的其他方法和姿勢,大家盡可以慢慢去摸索,這里僅僅是拋磚引玉。

至此,本篇講解完畢,歡迎大家繼續(xù)關(guān)注。

以上就是一文搞懂Java中的反射機(jī)制的詳細(xì)內(nèi)容,更多關(guān)于Java反射機(jī)制的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 成人欧美日韩高清不卡 | 国产精品九九九久久九九 | 国产精品亚洲玖玖玖在线靠爱 | 国产精品久久久久久亚洲伦理 | 呦女亚洲一区精品 | 久久久精品久久视频只有精品 | a级毛片无码免费真人 | 欧美日韩视频在线第一区 | 一区二区三区中文国产亚洲 | 中文字幕日韩一区二区 | 国产成人久久综合二区 | 全国男人的天堂网 | 99www综合久久爱com | 亚洲国产二区三区久久 | 日韩三级在线免费观看 | 亚洲在线一区二区三区 | 一区二区三区四区在线视频 | 国产一区二区播放 | 国产成人精品三级在线 | 99久女女精品视频在线观看 | 亚洲欧美日韩另类精品一区二区三区 | 一本色道久久综合网 | 欧美一级毛片欧美一级无片 | 国产精品亚洲高清一区二区 | 91精品最新国内在线播放 | 国内一区二区 | 亚洲成人性视频 | 亚洲视频在线观看网址 | 天天做天天爱夜夜大爽完整 | jyzzjyzz国产免费观看 | 美女做爰视频在线观看免费 | 手机免费看a | 国产小片 | 69交性视频| 久久综合香蕉久久久久久久 | 日本精品久久久久久久 | 国产精品精品国产一区二区 | 国产亚洲欧美一区 | 精品国产96亚洲一区二区三区 | 亚洲区免费 | 嫩模大尺度人体福利视频 |