反射
JAVA 反射機制是在運行狀態(tài)中胚吁,對于任意一個類牙躺,都能夠知道這個類的所有屬性和方 法;對于任意一個對象腕扶,都能夠調(diào)用它的任意一個方法和屬性孽拷;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為 java 語言的反射機制。
Java 反射機制半抱,可以實現(xiàn)以下功能:
①在運行時判斷任意一個對象所屬的類脓恕;
②在運行時構(gòu)造任意一個類的對象膜宋;
③在運行時判斷任意一個類所具有的成員變量和方法;
④在運行時調(diào)用任意一個對象的方法炼幔; ⑤生成動態(tài)代理秋茫。
一、 獲取源頭 Class(重點)
①Class.forName(”包名.類名”)//一般盡量采用該形式
②類.class
③對象.getClass()
public class Source {
public static void main(String[] args) {
//第一種方式:對象.class
Source s=new Source();
Class<?>c1=s.getClass();
//第二種方式:類.class
Class<?>c2=Source.class;
//第三種方式(推薦方式): Class.forName()
Class<?>c3=null;
try {
c3=Class.forName("com.shsxt.ref.simple.Source");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c1.getName());
System.out.println(c2.getName());
System.out.println(c3.getName());
}
}
1.創(chuàng)建對象的時候,拿到的都是當(dāng)天前類型Class對象的一個鏡像|賦值體
2.在類加載的時候,會在內(nèi)存中存在當(dāng)天前類型的一個Class對象,一個類的Class對象中存儲這個類的所有信息(屬性,方法,構(gòu)造器...)
3.只要我們能夠獲取這個類型的Class對象,就可以對這個類做一切操作
Class 類的實例表示正在運行的 Java 應(yīng)用程序中的類和接口
public class ReflectDemo02 {
public static void main(String[] args) throws ClassNotFoundException{
//1.對象.getClass()
Class cls1="哈哈".getClass();
Class cls2="呵呵".getClass();
System.out.println(cls1==cls2);
//2.類名.class
Class cls3=String.class;
System.out.println(cls1==cls3);
System.out.println(cls3);
//3.Class.forName("類的權(quán)限命名:包名+類名") 推薦
Class cls4=Class.forName("java.lang.String");
System.out.println(cls3==cls4);
//4.根據(jù)子類的Class對象獲取父類的Class對象
Class cls5=cls4.getSuperclass();
System.out.println(cls5);
//5.獲取基本數(shù)據(jù)類型的Class對象
Class base1=int.class;
System.out.println(base1);
Class cls6=Integer.class;
System.out.println(base1==cls6);
Class base2=Integer.TYPE; //得到對應(yīng)的基本數(shù)據(jù)類型的class對象
System.out.println(base1==base2);
//常用的方法
//1.getName() 包名+類名
System.out.println(cls5.getName());
//2. Class<?>[] getInterfaces()
Class[] arr=cls4.getInterfaces();
System.out.println(Arrays.toString(arr));
//3.String getSimpleName()
System.out.println(cls4.getSimpleName());
//4.boolean isInterface() isPrimitive()
System.out.println(Integer.class.isPrimitive());
System.out.println(Integer.TYPE.isPrimitive());
}
}
二乃秀、實例化對象****(****重點****)**
1)通過反射獲取到類中的構(gòu)造器
2)根據(jù)構(gòu)造器創(chuàng)建對象
l 構(gòu)造器Constructor對象.newInstance(實參)方法
l 直接通過class類的newIntance()方法創(chuàng)建對象,方法沒有參數(shù) 調(diào)用空構(gòu)造
構(gòu)造器方法
注意****:newInstance()****是調(diào)用空構(gòu)造肛著,如果空構(gòu)造不存在,會出現(xiàn)異常跺讯。由此可知枢贿,使用其他構(gòu)造器創(chuàng)建對象比較麻煩,使用空構(gòu)造非常簡單刀脏。 確本旨裕空構(gòu)造存在.
public class ReflectDemo03 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//1.先獲取類的Class
Class cls=Person.class;
//2.通過Class類中的方法,獲取到Person類中的構(gòu)造器
/*
* Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構(gòu)造方法愈污。
Constructor<?>[] getConstructors()
返回一個包含某些 Constructor 對象的數(shù)組耀态,這些對象反映此 Class 對象所表示的類的所有公共構(gòu)造方法。
*/
Constructor con1=cls.getConstructor(int.class,String.class,int.class);
Person p=(Person) con1.newInstance(01,"盧妹妹",18);
System.out.println(p);
Person p1=(Person)cls.newInstance();
System.out.println(p1);
/*
* Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回一個 Constructor 對象暂雹,該對象反映此 Class 對象所表示的類或接口的指定構(gòu)造方法茫陆。
Constructor<?>[] getDeclaredConstructors()
返回 Constructor 對象的一個數(shù)組,這些對象反映此 Class 對象表示的類聲明的所有構(gòu)造方法擎析。
*/
Constructor<Person>[] cons=cls.getDeclaredConstructors();
System.out.println(Arrays.toString(cons));
//私有的構(gòu)造器
//放開權(quán)限
cons[1].setAccessible(true); //權(quán)限方法
Person p3=cons[1].newInstance(02,"盧雙雙");
cons[1].setAccessible(false);
System.out.println(p3);
}
}
|
三:屬性和方法
獲取所有屬性(包括父類或接口) 簿盅,使用 Field 即可操作
獲取所有方法(包括父類或接口),使用 Method 即可揍魂。
package com.shsxt.ref01;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
public class ReflectDemo04 {
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
// testField(Person.class);
testMethod(Person.class);
}
/*
* 操作方法 調(diào)用方法,能給方法傳遞實參
*
* Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一個 Method 對象桨醋,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。
Method[] getDeclaredMethods()
Method getMethod(String name, Class<?>... parameterTypes)
返回一個 Method 對象现斋,它反映此 Class 對象所表示的類或接口的指定公共成員方法喜最。
Method[] getMethods()
返回一個包含某些 Method 對象的數(shù)組,這些對象反映此 Class 對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法庄蹋。
*/
public static void testMethod(Class cls) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{
Method[] arr=cls.getMethods();
Person p=(Person) cls.newInstance();
// Method me=cls.getDeclaredMethod("setAge", int.class);
Method me=cls.getDeclaredMethod("toString");
System.out.println(me.invoke(p));;
System.out.println(p.getAge());
// System.out.println(Arrays.toString(arr));
//靜態(tài)方法執(zhí)行的時候,invoke第一個參數(shù)可以為null
cls.getMethod("haha").invoke(null);
}
/*
* 反射操作類中的字段 能設(shè)置值 能獲取值
* Field getDeclaredField(String name)
返回一個 Field 對象瞬内,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。
Field[] getDeclaredFields()
返回 Field 對象的一個數(shù)組限书,這些對象反映此 Class 對象所表示的類或接口所聲明的所有字段虫蝶。
Field getField(String name)
返回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段倦西。
Field[] getFields()
*/
public static void testField(Class cls) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{
Field name=cls.getDeclaredField("name");
//Object get(Object obj) 返回指定對象上此 Field 表示的字段的值能真。
name.setAccessible(true);
//void set(Object obj, Object value)
Person p=new Person(05,"大力",18);
name.set(p, "大力水手");
System.out.println(name.get(p));
System.out.println(name.getName());
System.out.println(Modifier.toString(name.getModifiers()));
}
}
四:修飾符
獲取修飾符,使用 Modifier 即可
五:類加載器
在 java 中有三種類類加載器: ⑴Bootstrap ClassLoader 此加載器采用 c++編寫,一般開發(fā)中很少見粉铐。 ⑵Extension ClassLoader 用來進行擴展類的加載疼约,一般對應(yīng)的是 jre\lib\ext 目錄中的類 ⑶AppClassLoader 加載 classpath 指定的類,是最常用的加載器蝙泼。同時也是 java 中默認的加載器程剥。 了解即可。
了解一下類的生命周期 : 在一個類編譯完成之后汤踏,下一步就需要開始使用類织鲸,如果要使用一個類,肯定離不開 JVM茎活。 在程序執(zhí)行中 JVM 通過裝載,鏈接琢唾,初始化這 3 個步驟完成载荔。 類的裝載是通過類加載器完成的,加載器將.class 文件的二進制文件裝入 JVM 的方法區(qū)采桃,并且在堆區(qū)創(chuàng)建描述這個類的 java.lang.Class 對象懒熙。用來封裝數(shù)據(jù)。 但是同一個類只會被類裝載器裝載一次普办。 鏈接就是把二進制數(shù)據(jù)組裝為可以運行的狀態(tài)工扎。鏈接分為校驗,準備衔蹲,解析這 3 個階段 1肢娘、校驗一般用來確認此二進制文件是否適合當(dāng)前的 JVM(版本), 2舆驶、準備就是為靜態(tài)成員分配內(nèi)存空間橱健。并設(shè)置默認值 3、解析指的是轉(zhuǎn)換常量池中的代碼作為直接引用的過程沙廉,直到所有的符號引用都可以 被運行程序使用(建立完整的對應(yīng)關(guān)系) 完成之后拘荡,類型也就完成了初始化,初始化之后類的對象就可以正常使用了撬陵,直到一個 對象不再使用之后珊皿,將被垃圾回收。釋放空間巨税。當(dāng)沒有任何引用指向 Class 對象時就會被卸載蟋定,結(jié)束類的生命周期。