什么是java反射:
JAVA反射機制是在運行狀態(tài)中狱窘,對于任意一個類,都能夠知道這個類的所有屬性和方法货葬;對于任意一個對象,都能夠調(diào)用它的任意一個方法和屬性劲够;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機制。
注意:反射是指運行時的特性休傍。
在運行時征绎,首先你的代碼會先被編譯成一個.class文件,然后被類加載器加載到j(luò)vm內(nèi)存中磨取。
假設(shè)你寫了一段代碼:
Student ?stu = new Student();
你的類Student加載到方法區(qū)人柿,這時會創(chuàng)建一個Student的class對象到堆中,這個只是類的類型對象忙厌,每個類只有一個class對象凫岖,作為方法區(qū)類的數(shù)據(jù)結(jié)構(gòu)的借口。這都是在jvm創(chuàng)建對象之前執(zhí)行逢净,檢查類的加載情況哥放,找到類對應(yīng)的class對象,如果都已經(jīng)加載好爹土,則進行初始化:new Student()甥雕。
上面的代碼,我們自己寫好了需要創(chuàng)建的類胀茵,但是反射卻可以根據(jù)需求社露,動態(tài)的加載需要的類。通過以下代碼可以動態(tài)加載琼娘,例如:
Class stu = Class.forName();
下面使用代碼介紹一下具體的調(diào)用情況:
首先創(chuàng)建Student類峭弟,具體如下:
public class Student {
//---------------構(gòu)造方法-------------------
? ? //(默認的構(gòu)造方法)
? ? Student(String str){
System.out.println("(默認)的構(gòu)造方法 s = " + str);
? ? }
//無參構(gòu)造方法
? ? public Student(){
System.out.println("調(diào)用了公有、無參構(gòu)造方法執(zhí)行了脱拼。瞒瘸。。");
? ? }
//有一個參數(shù)的構(gòu)造方法
? ? public Student(char name){
System.out.println("姓名:" + name);
? ? }
//有多個參數(shù)的構(gòu)造方法
? ? public Student(String name, int age){
System.out.println("姓名:"+name+"年齡:"+ age);//這的執(zhí)行效率有問題挪拟,以后解決挨务。
? ? }
//受保護的構(gòu)造方法
? ? protected Student(boolean n){
System.out.println("受保護的構(gòu)造方法 n = " + n);
? ? }
//私有構(gòu)造方法
? ? private Student(int age){
System.out.println("私有的構(gòu)造方法? 年齡:"+ age);
? ? }
//**********字段*************//
? ? public Stringname;
? ? protected int age;
? ? char sex;
? ? private StringphoneNum;
? ? @Override
? ? public StringtoString() {
return "Student [name=" +name +", age=" +age +", sex=" +sex
? ? ? ? ? ? ? ? +", phoneNum=" +phoneNum +"]";
? ? }
public void show1(String s){
System.out.println("調(diào)用了:公有的,String參數(shù)的show1(): s = " + s);
? ? }
protected void show2(){
System.out.println("調(diào)用了:受保護的玉组,無參的show2()");
? ? }
void show3(){
System.out.println("調(diào)用了:默認的谎柄,無參的show3()");
? ? }
private Stringshow4(int age){
System.out.println("調(diào)用了,私有的惯雳,并且有返回值的朝巫,int參數(shù)的show4(): age = " + age);
? ? ? ? return "abcd";
? ? }
public static void main(String[] args) {
System.out.println("main方法執(zhí)行了。石景。劈猿。");
? ? }
}
1.獲取Class對象
獲取Class對象有三種方式:
1.1Object.getClass();
1.2獲取數(shù)據(jù)的Class屬性 ?obj.class
1.3通過靜態(tài)方法獲取 Class.forName();
測試類如下:
public?class?Fanshe?{??
public?static?void?main(String[]?args)?{??
//第一種方式獲取Class對象????
Student?stu1?=new?Student();//這一new?產(chǎn)生一個Student對象拙吉,一個Class對象。??
Class?stuClass?=?stu1.getClass();//獲取Class對象??
????????System.out.println(stuClass.getName());??
//第二種方式獲取Class對象 ?
Class?stuClass2?=?Student.class;??
System.out.println(stuClass?==?stuClass2);//判斷第一種方式獲取的Class對象和第二種方式獲取的是否是同一個??
//第三種方式獲取Class對象 ?
try?{??
Class?stuClass3?=?Class.forName("fanshe.Student");//注意此字符串必須是真實路徑揪荣,就是帶包名的類路徑筷黔,包名.類名??
System.out.println(stuClass3?==?stuClass2);//判斷三種方式是否獲取的是同一個Class對象??
}catch?(ClassNotFoundException?e)?{??
????????????e.printStackTrace();??
????????}??
? ? } ?
}
運行main得到的結(jié)果如下:
調(diào)用了公有、無參構(gòu)造方法執(zhí)行了仗颈。佛舱。。
zz.Student
true
true
2.獲取構(gòu)造方法
獲取構(gòu)造方法可以獲取到:
1.所有公有構(gòu)造方法
2.所有構(gòu)造方法
3.獲取某個構(gòu)造方法(公有挨决,私有请祖,默認,受保護)
測試類如下:
public class Constructors {
public static void main(String[] args)throws Exception {
//1.加載Class對象
? ? ? ? Class clazz = Class.forName("zz.Student");
? ? ? ? //2.獲取所有公有構(gòu)造方法
? ? ? ? System.out.println("**********************所有公有構(gòu)造方法*********************************");
? ? ? ? Constructor[] conArray = clazz.getConstructors();
? ? ? ? for(Constructor c : conArray){
System.out.println(c);
? ? ? ? }
System.out.println("************所有的構(gòu)造方法(包括:私有脖祈、受保護肆捕、默認、公有)***************");
? ? ? ? conArray = clazz.getDeclaredConstructors();
? ? ? ? for(Constructor c : conArray){
System.out.println(c);
? ? ? ? }
System.out.println("*****************獲取公有盖高、無參的構(gòu)造方法*******************************");
? ? ? ? Constructor con = clazz.getConstructor(null);
? ? ? ? //1>慎陵、因為是無參的構(gòu)造方法所以類型是一個null,不寫也可以:這里需要的是一個參數(shù)的類型,切記是類型
? ? ? ? //2>或舞、返回的是描述這個無參構(gòu)造函數(shù)的類對象荆姆。
? ? ? ? System.out.println("con = " + con);
? ? ? ? //調(diào)用構(gòu)造方法
? ? ? ? Object obj = con.newInstance();
? ? ? ? //? System.out.println("obj = " + obj);
//? Student stu = (Student)obj;
? ? ? ? System.out.println("******************獲取私有構(gòu)造方法,并調(diào)用*******************************");
? ? ? ? con = clazz.getDeclaredConstructor(char.class);
? ? ? ? System.out.println(con);
? ? ? ? //調(diào)用構(gòu)造方法
? ? ? ? con.setAccessible(true);//暴力訪問(忽略掉訪問修飾符)
? ? ? ? obj = con.newInstance('男');
? ? }
}
輸出結(jié)果如下:
**********************所有公有構(gòu)造方法*********************************
public zz.Student(java.lang.String,int)
public zz.Student()
public zz.Student(char)
************所有的構(gòu)造方法(包括:私有映凳、受保護胆筒、默認、公有)***************
private zz.Student(int)
protected zz.Student(boolean)
public zz.Student(java.lang.String,int)
zz.Student(java.lang.String)
public zz.Student()
public zz.Student(char)
*****************獲取公有诈豌、無參的構(gòu)造方法*******************************
con = public zz.Student()
調(diào)用了公有仆救、無參構(gòu)造方法執(zhí)行了。矫渔。彤蔽。
******************獲取私有構(gòu)造方法,并調(diào)用*******************************
public zz.Student(char)
姓名:男
3.獲取成員變量
測試類如下:
public class Fields {
public static void main(String[] args)throws Exception {
//1.獲取Class對象
? ? ? ? Class stuClass = Class.forName("zz.Student");
? ? ? ? //2.獲取字段
? ? ? ? System.out.println("************獲取所有公有的字段********************");
? ? ? ? Field[] fieldArray = stuClass.getFields();
? ? ? ? for(Field f : fieldArray){
System.out.println(f);
? ? ? ? }
System.out.println("************獲取所有的字段(包括私有庙洼、受保護顿痪、默認的)********************");
? ? ? ? fieldArray = stuClass.getDeclaredFields();
? ? ? ? for(Field f : fieldArray){
System.out.println(f);
? ? ? ? }
System.out.println("*************獲取公有字段**并調(diào)用***********************************");
? ? ? ? Field f = stuClass.getField("name");
? ? ? ? System.out.println(f);
? ? ? ? //獲取一個對象
? ? ? ? Object obj = stuClass.getConstructor().newInstance();//產(chǎn)生Student對象--》Student stu = new Student();
? ? ? ? //為字段設(shè)置值
? ? ? ? f.set(obj, "劉德華");//為Student對象中的name屬性賦值--》stu.name = "劉德華"
? ? ? ? //驗證
? ? ? ? Student stu = (Student)obj;
? ? ? ? System.out.println("驗證姓名:" + stu.name);
? ? ? ? System.out.println("**************獲取私有字段****并調(diào)用********************************");
? ? ? ? f = stuClass.getDeclaredField("phoneNum");
? ? ? ? System.out.println(f);
? ? ? ? f.setAccessible(true);//暴力反射,解除私有限定
? ? ? ? f.set(obj, "18888889999");
? ? ? ? System.out.println("驗證電話:" + stu);
? ? }
}
輸出結(jié)果如下:
************獲取所有公有的字段********************
public java.lang.String zz.Student.name
************獲取所有的字段(包括私有油够、受保護蚁袭、默認的)********************
public java.lang.String zz.Student.name
protected int zz.Student.age
char zz.Student.sex
private java.lang.String zz.Student.phoneNum
*************獲取公有字段**并調(diào)用***********************************
public java.lang.String zz.Student.name
調(diào)用了公有、無參構(gòu)造方法執(zhí)行了石咬。揩悄。。
驗證姓名:劉德華
**************獲取私有字段****并調(diào)用********************************
private java.lang.String zz.Student.phoneNum
驗證電話:Student [name=劉德華, age=0, sex= , phoneNum=18888889999]
4.獲取成員方法
測試類如下:
public class MethodClass {
public static void main(String[] args)throws Exception {
//1.獲取Class對象
? ? ? ? Class stuClass = Class.forName("zz.Student");
? ? ? ? //2.獲取所有公有方法
? ? ? ? System.out.println("***************獲取所有的”公有“方法*******************");
? ? ? ? stuClass.getMethods();
? ? ? ? Method[] methodArray = stuClass.getMethods();
? ? ? ? for(Method m : methodArray){
System.out.println(m);
? ? ? ? }
System.out.println("***************獲取所有的方法鬼悠,包括私有的*******************");
? ? ? ? methodArray = stuClass.getDeclaredMethods();
? ? ? ? for(Method m : methodArray){
System.out.println(m);
? ? ? ? }
System.out.println("***************獲取公有的show1()方法*******************");
? ? ? ? Method m = stuClass.getMethod("show1", String.class);
? ? ? ? System.out.println(m);
? ? ? ? //實例化一個Student對象
? ? ? ? Object obj = stuClass.getConstructor().newInstance();
? ? ? ? m.invoke(obj, "劉德華");
? ? ? ? System.out.println("***************獲取私有的show4()方法******************");
? ? ? ? m = stuClass.getDeclaredMethod("show4", int.class);
? ? ? ? System.out.println(m);
? ? ? ? m.setAccessible(true);//解除私有限定
? ? ? ? Object result = m.invoke(obj, 20);//需要兩個參數(shù)删性,一個是要調(diào)用的對象(獲取有反射)亏娜,一個是實參
? ? ? ? System.out.println("返回值:" + result);
? ? }
}
輸出結(jié)果如下:
***************獲取所有的”公有“方法*******************
public static void zz.Student.main(java.lang.String[])
public java.lang.String zz.Student.toString()
public void zz.Student.show1(java.lang.String)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
***************獲取所有的方法,包括私有的*******************
public static void zz.Student.main(java.lang.String[])
public java.lang.String zz.Student.toString()
public void zz.Student.show1(java.lang.String)
private java.lang.String zz.Student.show4(int)
protected void zz.Student.show2()
void zz.Student.show3()
***************獲取公有的show1()方法*******************
public void zz.Student.show1(java.lang.String)
調(diào)用了公有蹬挺、無參構(gòu)造方法執(zhí)行了维贺。。汗侵。
調(diào)用了:公有的幸缕,String參數(shù)的show1(): s = 劉德華
***************獲取私有的show4()方法******************
private java.lang.String zz.Student.show4(int)
調(diào)用了,私有的晰韵,并且有返回值的,int參數(shù)的show4(): age = 20
返回值:abcd
5.反射main方法
測試類如下:
public class Main {
public static void main(String[] args) {
try {
//1熟妓、獲取Student對象的字節(jié)碼
? ? ? ? ? ? Class clazz = Class.forName("zz.Student");
? ? ? ? ? ? //2雪猪、獲取main方法
? ? ? ? ? ? Method methodMain = clazz.getMethod("main", String[].class);//第一個參數(shù):方法名稱,第二個參數(shù):方法形參的類型起愈,
? ? ? ? ? ? //3只恨、調(diào)用main方法
? ? ? ? ? ? // methodMain.invoke(null, new String[]{"a","b","c"});
? ? ? ? ? ? //第一個參數(shù),對象類型抬虽,因為方法是static靜態(tài)的官觅,所以為null可以,第二個參數(shù)是String數(shù)組阐污,這里要注意在jdk1.4時是數(shù)組休涤,jdk1.5之后是可變參數(shù)
? ? ? ? ? ? //這里拆的時候?qū)? new String[]{"a","b","c"} 拆成3個對象。笛辟。功氨。所以需要將它強轉(zhuǎn)。
? ? ? ? ? ? methodMain.invoke(null, (Object)new String[]{"a","b","c"});//方式一
? ? ? ? ? ? // methodMain.invoke(null, new Object[]{new String[]{"a","b","c"}});//方式二
? ? ? ? }catch (Exception e) {
e.printStackTrace();
? ? ? ? }
}
}
輸出結(jié)果如下:
main方法執(zhí)行了手幢。捷凄。。
6.通過配置文件反射
測試類如下:
public class Demo {
public static void main(String[] args)throws Exception {
//通過反射獲取Class對象
? ? ? ? Class stuClass = Class.forName(getValue("className"));//"zz.Student"
? ? ? ? //2獲取show()方法
? ? ? ? Method m = stuClass.getMethod(getValue("methodName"));//show
? ? ? ? //3.調(diào)用show()方法
? ? ? ? m.invoke(stuClass.getConstructor().newInstance());
? ? }
//此方法接收一個key围来,在配置文件中獲取相應(yīng)的value
? ? public static StringgetValue(String key)throws IOException{
Properties pro =new Properties();//獲取配置文件的對象
? ? ? ? FileReader in =new FileReader("demo.txt");//獲取輸入流
? ? ? ? pro.load(in);//將流加載到配置文件對象中
? ? ? ? in.close();
? ? ? ? return pro.getProperty(key);//返回根據(jù)key獲取的value值
? ? }
}
配置文件如下:
className = zz.Student
methodName = show1
輸出結(jié)果如下:
調(diào)用了:公有的跺涤,String參數(shù)的show1(): s =
由此可見,調(diào)用其他方法只需要改寫配置文件即可监透,或者引入新的類也可以直接改寫配置文件桶错。
7.java泛型檢查
測試類如下:
public class Demo2 {
public static void main(String[] args)throws Exception{
ArrayList strList =new ArrayList<>();
? ? ? ? strList.add("aaa");
? ? ? ? strList.add("bbb");
? ? ? ? //? strList.add(100);
? ? ? ? //獲取ArrayList的Class對象,反向的調(diào)用add()方法才漆,添加數(shù)據(jù)
? ? ? ? Class listClass = strList.getClass(); //得到 strList 對象的字節(jié)碼 對象
? ? ? ? //獲取add()方法
? ? ? ? Method m = listClass.getMethod("add", Object.class);
? ? ? ? //調(diào)用add()方法
? ? ? ? m.invoke(strList, 100);
? ? ? ? //遍歷集合
? ? ? ? for(Object obj : strList){
System.out.println(obj);
? ? ? ? }
}
}
輸出結(jié)果如下:
aaa
bbb
100
個人公號:【排骨肉段】牛曹,可以關(guān)注一下。