基于java中反射的總結(jié)分析
剛開始學(xué)習(xí)java的時(shí)候真的很難理解反射到底是個(gè)什么東西
一些書籍,哪怕是很經(jīng)典的書籍都解釋的讓人感覺懵懵的,或許的確是我太笨
況且,網(wǎng)上說在將來學(xué)習(xí)框架的時(shí)候需要經(jīng)常應(yīng)用到反射機(jī)制,這樣一來總讓人心里有些不安
就方才偶然又把講解反射的章節(jié)和視頻看了一點(diǎn),覺得能理解一些了
現(xiàn)在決定一鼓作氣,邊看邊寫,順便把一些主要的內(nèi)容和操作都記載到這里
我想,對于我這么一個(gè)笨笨的人來說,學(xué)習(xí)的最好方法也許就是不斷重復(fù)
遇到不懂的知識就停下來把以往的重新學(xué)一遍,雖然浪費(fèi)了很多時(shí)間,但對我也有些效果
我的理解是:所謂反射,就是根據(jù)一個(gè)已經(jīng)實(shí)例化了的對象來還原類的完整信息
至少對我而言,我認(rèn)為它帶給我的好處是,讓我從下往上的又了解了一遍面向?qū)ο?/P>
x_x 在此又痛恨一邊那些厚部頭們,把我的腦細(xì)胞搞死一片
Class類
如果要完成反射,那么必須了解Class類
實(shí)例1:通過對象取得包名和類名package org.siu;
class Test {
}
public class Demo {
public static void main(String[] args) {
Test t = new Test();
System.out.println(t.getClass());
System.out.println(t.getClass().getName());
}
}
編譯結(jié)果如下,注意包的編譯方式即可
此處的getClass()方法是默認(rèn)繼承自O(shè)bject類的
在java中,Object類是所有類的父類,同樣,所有類的實(shí)例化對象也都是Class類的實(shí)例
因此,這樣一來就會牽扯到向上轉(zhuǎn)型和向下轉(zhuǎn)型的概念
由于向下轉(zhuǎn)型的不安全因素,在這里泛型也會接踵而來
(不過我想說的是,此處的泛型設(shè)計(jì)很刺眼!尼瑪,整個(gè)java的語法設(shè)計(jì)同樣刺眼,超惡心!?。。?/P>
實(shí)例2:Class類的實(shí)例化
由于Class類沒有構(gòu)造方法,所以實(shí)例化Class類的方式有點(diǎn)特殊,有三種方式:
類.Class
forName( )
class Test {
}
public class Demo {
public static void main(String[] args) {
//方式一:
Test t = new Test();
Class<? extends Test> c1 = t.getClass();
System.out.println(c1);
//方式二:
//為了避免特殊性,這里不用Test類,而用java庫中的String類
Class<String> c2 = String.class;
System.out.println(c2);
//方式三:
//forName()方法會拋出異常
Class<?> c3 = null;
try {
c3 = Class.forName("Test");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c3);
}
}
其中,forName( )方法需要重點(diǎn)掌握,因?yàn)樗梢栽陬惒淮_定的情況下實(shí)例化Class,更具靈活性
Class類的應(yīng)用
Class類中有一個(gè)方法叫做newInstance( ),它可以用來創(chuàng)建一個(gè)Class類對象的新實(shí)例
怎么說呢?Class對象包含的內(nèi)容就是反射好的那個(gè)類,我們要構(gòu)造那個(gè)類的新實(shí)例(新對象)
實(shí)例3:Class類的無參構(gòu)造對象public class Demo {
public static void main(String[] args) {
//實(shí)例化Class對象,forName()方法會拋異常
Class<?> c = null;
try {
//這里需要完整的包名和類名
c = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//生成一個(gè)字符串的引用
String s = null;
try {
//將構(gòu)造好的對象向下轉(zhuǎn)型為String類
//newInstance()方法會拋異常
s = (String) c.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("字符串長度: " + s.length());
}
}
這樣就通過無參數(shù)的形式構(gòu)造了一個(gè)新的對象,如同正常模式中
通過無參構(gòu)造方法來構(gòu)造新對象一樣
我們知道,類中除了有無參構(gòu)造方法,還會存在有參數(shù)的構(gòu)造方法
那在反射中如何通過有參數(shù)的形式構(gòu)造對象呢?接著看
實(shí)例4:Class類的有參構(gòu)造對象
import java.lang.reflect.Constructor;
public class Demo {
//下面的幾個(gè)方法拋出來的異常太多,為了代碼的緊湊性,這里就直接拋給虛擬機(jī)了
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
char[] ch = {'h','e','l','l','o'};
String s = null;
//獲得Class類對象的有參構(gòu)造方法,括號里面參數(shù)的寫法是:類型.class
Constructor<?> con = c.getConstructor(char[].class);
//用此構(gòu)造方法構(gòu)造一個(gè)新的字符串對象,參數(shù)為一個(gè)char數(shù)組
s = (String) con.newInstance(ch);
System.out.println("構(gòu)造的字符串:" + s);
}
}
我們還是使用String類做例,因?yàn)镾tring類用的比較多,便于理解
這里需要注意的是,構(gòu)造方法需要使用getConstructor( )方法獲得
至于參數(shù)類型則是:原有類型.class
還有一點(diǎn),無論是有參還是無參,這里所使用的構(gòu)造方法,原本的類里面必須對應(yīng)存在
那么,如何才能知道原有類里面的構(gòu)造方法,普通方法,繼承的父類等詳細(xì)信息呢?接著看
獲取類的結(jié)構(gòu)
要通過反射獲取類的結(jié)構(gòu)我們這里要導(dǎo)入一個(gè)新的包java.lang.reflect
實(shí)例5:取得類的構(gòu)造方法import java.lang.reflect.Constructor;
import java.util.Arrays;
public class Demo {
//下面的幾個(gè)方法拋出來的異常太多,為了代碼的緊湊性,這里就直接拋給虛擬機(jī)了
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("java.lang.Boolean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//這里的getConstructors()方法返回的是一個(gè)Constructor數(shù)組
Constructor<?>[] cons = c.getConstructors();
//打印的方式你可以自己寫,為了方便我用Arrays.toString(),湊合著看
System.out.println(Arrays.toString(cons));
}
}
我選擇了Boolean類來做例,因?yàn)锽oolean類的構(gòu)造方法就兩個(gè),方便看
實(shí)例6:取得類所實(shí)現(xiàn)的接口
import java.util.Arrays;
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("java.lang.Boolean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class<?>[] in = c.getInterfaces();
System.out.println(Arrays.toString(in));
}
}
沒什么好說的,看結(jié)果
實(shí)例7:取得父類
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("java.lang.Boolean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//注意了,這里不會是數(shù)組,why?
Class<?> su = c.getSuperclass();
System.out.println(su);
}
}
別忘了,java中是單繼承,父類只有一個(gè)
實(shí)例8:取得類的全部方法
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("java.lang.Boolean");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method[] m = c.getMethods();
//好吧,這次我就大發(fā)慈悲的寫個(gè)打印列表出來
for (int i = 0; i < m.length; i++) {
System.out.println(m[i]);
}
}
}
截取一部分,看看,意思下就行了……這幾個(gè)例子都比較簡單
實(shí)例9:取得本類的全部屬性
import java.lang.reflect.Field;
class Person {
private String name;
private int age;
}
public class Demo {
public static void main(String[] args) throws Exception {
Class<?> c = null;
try {
c = Class.forName("Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Field[] f = c.getDeclaredFields();
for (int i = 0; i < f.length; i++) {
System.out.println(f[i]);
}
}
}
getDeclaredFielsd()方法可以獲取全部屬性,getFields()只能獲取公共屬性
實(shí)例10:獲取本類中屬性的值
import java.lang.reflect.Field;
class Person {
public String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Demo {
public static void main(String[] args) throws Exception {
Person p = new Person("zhangsan",12);
Class<?> c = p.getClass();
//獲取公共屬性的值
Field f1 = c.getField("name");
//get(p)表明要獲取是哪個(gè)對象的值
String str = (String) f1.get(p);
System.out.println("姓名: " + str);
//獲取私有屬性的值
Field f2 = c.getDeclaredField("age");
//age是私有屬性,所以要設(shè)置安全檢查為true
f2.setAccessible(true);
int age = (int) f2.get(p);
System.out.println("年齡: " + age);
}
}
要注意的是:setAccessible()方法可以設(shè)置是否訪問和修改私有屬性
坦白說,java學(xué)到現(xiàn)在我還沒發(fā)現(xiàn)什么能亮瞎我鈦金眼的知識在里邊
每次都是寫一堆繁瑣的語法實(shí)現(xiàn)個(gè)小玩意兒,不然就是拼命調(diào)用API,拼命的拋異常
讓本身顯得不夠緊湊的代碼變得愈發(fā)累贅
如果我喜歡一門語言,在我利用它做出東西來之前,它本身的特性必須能夠打動我
顯然,java并不讓我快樂,也許很多程序員跟我一樣是被迫使用java的
僅以此來安撫我那顆孤獨(dú)編碼的心,下面接著看內(nèi)容
反射的應(yīng)用實(shí)例11:通過反射修改屬性
import java.lang.reflect.Field;
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String toString() {
return "姓名: " + this.name;
}
}
public class Demo {
public static void main(String[] args) throws Exception {
Person p = new Person("王二狗");
System.out.println(p);
Class<?> c = p.getClass();
//定義要修改的屬性
Field f = c.getDeclaredField("name");
f.setAccessible(true);
//修改屬性,傳入要設(shè)置的對象和值
f.set(p, "張二蛋");
System.out.println(p);
}
}
幾個(gè)方法都是有聯(lián)系的,如果看不懂就先熟悉上面幾個(gè)例子
實(shí)例12:通過反射調(diào)用方法
import java.lang.reflect.Method;
class Person {
public void print(int i) {
System.out.println("我在寫數(shù)字: " + i);
}
public static void say(String str) {
System.out.println("我在說: " + str);
}
}
public class Demo {
public static void main(String[] args) throws Exception {
Person p = new Person();
Class<?> c = p.getClass();
//getMethod()方法需要傳入方法名,和參數(shù)類型
Method m1 = c.getMethod("print", int.class);
//invoke()表示調(diào)用的意思,需要傳入對象和參數(shù)
m1.invoke(p, 10);
Method m2 = c.getMethod("say", String.class);
//這里的null表示不由對象調(diào)用,也就是靜態(tài)方法
m2.invoke(null, "你妹");
}
}
這里演示了一個(gè)普通的有參方法和一個(gè)靜態(tài)方法
既然有參數(shù)的都寫出來了,那么無參的就更簡單了,直接傳入一個(gè)對象即可
實(shí)例13:通過反射操作數(shù)組
import java.lang.reflect.Array;
public class Demo {
public static void main(String[] args) throws Exception {
int[] arr = {1,2,3,4,5};
Class<?> c = arr.getClass().getComponentType();
System.out.println("數(shù)組類型: " + c.getName());
int len = Array.getLength(arr);
System.out.println("數(shù)組長度: " + len);
System.out.print("遍歷數(shù)組: ");
for (int i = 0; i < len; i++) {
System.out.print(Array.get(arr, i) + " ");
}
System.out.println();
//修改數(shù)組
System.out.println("修改前的第一個(gè)元素: " + Array.get(arr, 0));
Array.set(arr, 0, 3);
System.out.println("修改后的第一個(gè)元素: " + Array.get(arr, 0));
}
}
這里要注意一點(diǎn),getComponentType( )返回的是數(shù)組元素的Class
暫時(shí)就寫這么多,我看的書中還有反射在工廠模式中的應(yīng)用
無非是用forName()方法替換一下,沒什么可說的
我是個(gè)java初級黑,我恨java那種惡心的語法和設(shè)計(jì)
這都是為了Android,為了打基礎(chǔ),為了適應(yīng)以后的工作
- java類加載器和類反射使用示例
- java反射機(jī)制實(shí)戰(zhàn)示例分享
- java反射使用示例分享
- java根據(jù)方法名稱取得反射方法的參數(shù)類型示例
- java反射機(jī)制示例詳解
- java使用dom4j解析xml配置文件實(shí)現(xiàn)抽象工廠反射示例
- java反射實(shí)現(xiàn)javabean轉(zhuǎn)json實(shí)例代碼
- Java反射機(jī)制的學(xué)習(xí)總結(jié)
- Java 采用反射獲取class屬性值的實(shí)現(xiàn)代碼
- 基于Java回顧之反射的使用分析
- Java反射機(jī)制的實(shí)現(xiàn)詳解
- Java 反射獲取類詳細(xì)信息的常用方法總結(jié)
- AJAX JavaScript反射機(jī)制的介紹
- Java反射學(xué)習(xí) getClass()函數(shù)應(yīng)用
- Java 反射之私有字段和方法詳細(xì)介紹
- java反射應(yīng)用詳細(xì)介紹
- 傳智播客學(xué)習(xí)之java 反射
- java反射android的r文件的示例
相關(guān)文章
IDEA配置Maven并版本統(tǒng)一管理的實(shí)現(xiàn)
本文主要介紹了IDEA配置Maven并版本統(tǒng)一管理的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09mybatis框架xml下trim中的prefix與suffix等標(biāo)簽的用法
這篇文章主要介紹了mybatis框架xml下trim中的prefix與suffix等標(biāo)簽的用法,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07帶你詳細(xì)了解Spring Security的注解方式開發(fā)
這篇文章主要介紹了詳解spring security四種實(shí)現(xiàn)方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-08-08Nacos后臺頻繁打印get changedGroupKeys:[]的問題及解決
這篇文章主要介紹了Nacos后臺頻繁打印get changedGroupKeys:[]的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01Java對象級別與類級別的同步鎖synchronized語法示例
這篇文章主要為大家介紹了Java對象級別與類級別的同步鎖synchronized語法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03Spring Boot下如何自定義Repository中的DAO方法
這篇文章主要介紹了Spring Boot下如何自定義Repository中的DAO方法,需要的朋友可以參考下2017-06-06