1. 類加載過程
Java是一門編譯加解析的語言,編譯器先將代碼編譯成字節碼文件(class文件),Jvm加載class文件進行解析運行!
類加載通常分三個步驟:class文件的加載、類的鏈接、類的初始化!
1.1 class文件的加載:
將編譯後的class文件,加載到內存中,解析字節碼,並生成一個Class對象!
1.1.1 類加載器介紹:
class文件的加載,並不是通過一個加載器實現,是通過多組類加載器共同實現的,共分四類:根類加載器、擴展類加載器、系統類加載器、用戶類加載器!
根類加載器:在sun.boot.class.path系統變量中的路徑中尋找class文件,並進行加載!
擴展類加載器:在java.ext.dirs系統變量中的路徑中尋找class文件,並進行加載!類型爲ExtClassLoader
系統類加載器:在java.class.path系統變量中的路徑中尋找class文件,並進行加載!類型爲AppClassLoader;可以通過ClassLoader.getSystemClassLoader()靜態方法獲取!
用戶類加載器:用戶自定義類加載器,根據自定義邏輯進行類加載,一般情況下父類加載器爲系統類加載器!
Ps:
- Jvm系統變量可以通過System.getProperties()方式獲取並查看!
- 上面四類類加載是存在層級關係的,從上到下:根類加載器、擴展類加載器、系統類加載器、用戶類加載器
- 上面四類類加載器只有根類加載器不是ClassLoader的子類,其餘類加載器都是ClassLoader的子類,因爲根類加載器是Jvm實現!
1.1.2 類加載過程介紹:
當加載一個類的時候,首先判斷緩存中是否存在,如果不存在,會通過當前使用的類加載器找到根類加載器,然後一層層向下使用類加載器尋找class文件,加載成功後,退出並返回Class對象;如果到用戶類加載器依然沒有找到class文件,Jvm拋出ClassNotFoundException!(手動進行類加載的時候,可以指定類加載器;如果依賴於Jvm自動進行類加載的時候,默認使用系統類加載器)
1.1.3 自定義類加載器:
可以通過繼承ClassLoader類,來實現自定義用戶類加載器,主要通過重寫loadClass()和findClass()兩個方法來實現,具體細節不再展開描述!好處就是可以定製特定類加載前的部分實現邏輯!
1.2 類的鏈接:
將class文件加載到內存中的二進制數據合併到JRE中:
1.3 類的初始化:
- 對類變量進行初始化賦值
- 執行靜態初始化代碼塊
Ps:
- 調用ClassLoader.loadClass(類名)只會執行類的加載和鏈接,不會進行類的初始化,等到類使用的時候纔會執行初始化!
- 調用Class.forName(類名)會執行類的加載、鏈接、並強制初始化!
1.4 觸發類加載條件:
- 創建類實例
- 訪問類方法
- 訪問類成員
- 調用Class.forName()方法
- 加載子類的時候,會先加載所有父類
- 直接使用java.exe命令運行某個主類,會先加載主類
Ps:訪問static final屬性的類成員變量,如果該對象在編譯期間就能確定內容;編譯器會在使用它的地方直接替換爲它的值,因此訪問的時候,不通過類訪問,所以不會觸發類加載!
2. Java的反射機制
2.1 反射機制的原理:
Java中的反射是通過類加載後生成的Class對象實現的,該對象提供了所有的類操作和類信息獲取能力!
獲取Class對象的方法:
- 調用Class.forName()類方法,獲取Class對象!
- 類.class,通過類的class屬性,獲取Class對象!
- 通過對象調用Object.getClass()實例方法,獲取Class對象!
Ps:後面兩種方式,必須保證類加載已經完成,否則無法獲取;Class.forName()方式可以在類沒有加載的時候調用,觸發類加載!
2.2 通過反射獲取信息:
2.2.1 獲取構造器、獲取成員、獲取方法相關信息:
Ps:
- getXXX獲取某個特定類型的public屬性的數據!
- getXXXs獲取所有public屬性的數據!
- getDeclaredXXX獲取某個特定類型的所有屬性的數據!
- getDeclaredXXXs獲取所有屬性的數據!
- 數據獲取的時候,都是包括繼承的數據!!!
2.2.2 獲取類相關信息:
/*獲取Class對象所屬的外部類*/
public Class<?> getDeclaringClass() throws SecurityException
/*獲取類中的所有內部類*/
public Class<?>[] getDeclaredClasses() throws SecurityException
/*獲取類中所有public屬性的內部類*/
public Class<?>[] getClasses()
/*獲取類實現的接口*/
public Class<?>[] getInterfaces()
/*獲取類繼承的父類*/
public native Class<? super T> getSuperclass()
2.2.3 獲取註解相關信息:
/*獲取指定類型的註解, 包括父類註解*/
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
/*獲取指定類型的註解,不包括父類註解*/
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass)
/*獲取當前類的所有註解,包括父類註解*/
public Annotation[] getAnnotations()
/*獲取當前類的所有註解,不包括父類註解*/
public Annotation[] getDeclaredAnnotations()
/*針對Java8 重複註解功能,提供的獲取指定類型註解,包括父類註解*/
public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass)
/*針對Java8 重複註解功能,提供的獲取指定類型註解,不包括父類註解*/
public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass)
2.2.4 獲取類基本信息:
/*獲取包信息*/
public Package getPackage()
/*獲取類名字*/
public String getName()
/*獲取類的簡稱*/
public String getSimpleName()
/*獲取類的修飾符常量值,通過Modifier工具類解碼*/
public native int getModifiers()
/*class信息判斷*/
/*判斷obj對象是否屬於當前類的實例,與instanceof用法一致*/
public native boolean isInstance(Object obj)
/*判斷當前類是否是一個接口*/
public native boolean isInterface()
/*判斷當前類是否是一個數組類*/
public native boolean isArray()
/*判斷當前類是否爲基礎類類型,Boolean、Character、Byte、Short、Integer、Long、Double、Void*/
public native boolean isPrimitive()
/*判斷當前類是否是一個枚舉類*/
public boolean isEnum()
/*判斷當前類是否是一個匿名類*/
public boolean isAnonymousClass()
/*判斷當前類是否被annotationClass註解修飾*/
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
instanceof與isInstatnce解析:
public class InstanceTest
{
public static void main(String[] args)
{
ClassF f = new ClassF();
ClassS s = new ClassS();
/*instanceof Test*/
System.out.println("instanceof Test");
/*class是object本身類,編譯通過,返回true*/
System.out.println(f instanceof ClassF);
/*class是object父類,編譯通過,返回true*/
System.out.println(s instanceof ClassF);
/*class是object子類,編譯通過,返回false*/
System.out.println(f instanceof ClassS);
/*class與object不存在任何關係,編譯報錯!!!*/
//System.out.println(f instanceof String);
/*isInstance Test*/
System.out.println("isInstance Test");
/*class是object本身類,編譯通過,返回true*/
System.out.println(ClassF.class.isInstance(f));
/*class是object父類,編譯通過,返回true*/
System.out.println(ClassF.class.isInstance(s));
/*class是object子類,編譯通過,返回false*/
System.out.println(ClassS.class.isInstance(f));
/*class與object不存在任何關係,編譯通過,返回false*/
System.out.println(String.class.isInstance(f));
}
}
class ClassS extends ClassF
{
}
class ClassF
{
}
Ps:
- instanceof是關鍵詞,isInstance是Class對象的方法
- 兩者用法基本相同,只是當class與object沒有關係的時候,instanceof編譯報錯;isInstance編譯通過,返回false!
2.2.5 獲取方法的參數信息:
Java8,Method類和Constructor類新增了一個共同的抽象類Executable,Executable類中提供了一系列關於Parameter類的方法:
/*Executable類主要方法*/
/*獲取方法或構造器的參數個數*/
public int getParameterCount()
/*獲取方法或構造器的參數類型數組*/
public Type[] getGenericParameterTypes()
/*獲取方法或構造器的參數數組*/
public Parameter[] getParameters()
Parameter類中也提供了一系列獲取具體參數信息的方法(獲取參數類型、獲取參數修飾符、獲取參數名、獲取參數泛型類型、參數是否可變參數等等):
2.3 通過反射操作類:
java.lang.reflect包中除了提供了Class類,同時也提供了Package、Method、Field、Constructor、Array、Type、ParameterizedType等類,爲獲取到的反射數據提供操作能力!
2.3.1 創建對象:
通過反射創建對象有兩種方式:Class對象的newInstance方法和Constructor對象的newInstance方法!
public class ReflectTest
{
public static void main(String[] args)
{
/*通過反射創建對象的兩種方式*/
/*通過Class對象的newInstance()方法,只能訪問public屬性的構造器*/
try
{
ReflectPublic r1 = ReflectPublic.class.newInstance();
r1.hello();
}
catch (Exception e)
{
e.printStackTrace();
}
/*通過Constructor對象的newInstance()方法,可以通過setAccessible設置,不進行訪問權限檢測,訪問private屬性的構造器*/
Constructor<ReflectPrivate> constructor;
try
{
constructor = ReflectPrivate.class.getDeclaredConstructor();
constructor.setAccessible(true);
ReflectPrivate r2 = constructor.newInstance();
r2.hello();
}
catch (Exception e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
class ReflectPrivate
{
private ReflectPrivate()
{
}
public void hello()
{
System.out.println("private hello");
}
}
class ReflectPublic
{
public ReflectPublic()
{
}
public void hello()
{
System.out.println("public hello");
}
}
Ps:setAccessible()不進行類型訪問權限設置,同樣可以使用在Method和Field兩個類,用來訪問private屬性的方法和成員!
2.3.2 調用方法:
通過Method類中的invoke方法進行方法調用(Object入參爲null,調用靜態方法)!
public class MothodTest
{
public static void main(String[] args)
{
try
{
/*通過反射調用類的靜態方法*/
Method method = ReflectMothod.class.getMethod("staticfun");
method.invoke(null);
/*通過反射對象的實例方法*/
ReflectMothod r = new ReflectMothod();
Method method1 = ReflectMothod.class.getMethod("fun");
method1.invoke(r);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
class ReflectMothod
{
public static void staticfun()
{
System.out.println("staticfun()");
}
public static void fun()
{
System.out.println("fun()");
}
}
2.3.3 訪問成員:
代碼示例:
public class FieldTest
{
public static void main(String[] args)
{
ReflectField r = new ReflectField();
r.i = 1;
r.s = "hello";
try
{
/*獲取普通類型的實例成員,並修改*/
Field field = ReflectField.class.getField("i");
System.out.println(field.getInt(r));
field.setInt(r, 100);
/*獲取引用類型的實例成員,並修改*/
Field field1 = ReflectField.class.getField("s");
System.out.println(field1.get(r));
field1.set(r, "hello100");
/*獲取類靜態成員,並修改*/
Field field2 = ReflectField.class.getField("b");
System.out.println(field2.getBoolean(null));
field2.setBoolean(null, true);
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println(r.i);
System.out.println(r.s);
System.out.println(ReflectField.b);
}
}
class ReflectField
{
public int i;
public String s;
public static boolean b;
}
結果輸出:
2.3.4 操作數組:
java.lang.reflect包中還提供了一個Array類,用來進行數組類型的反射行爲!
public class ArrayTest
{
public static void main(String[] args)
{
int[] a = new int[5];
/*通過Array類反射創建數組*/
int[] a1 = (int [])Array.newInstance(int.class, 5);
/*通過Array類反射操作數組*/
Array.set(a1, 0, 1);
System.out.println(Array.get(a1, 0));
}
}
3. 動態代理:
Java基於反射的動態代理就是,將一個接口中的所有方法實現都抽象到InvocationHandler接口中的invoke方法中,再通過Proxy或者其子類創建這個接口的實現類,實現類中通過InvocationHandler接口中的invoke方法來代理原接口中的方法!
public class ReflectProxyTest
{
public static void main(String[] args)
{
/*通過Proxy.newProxyInstance方法,創建ReflectProxy接口的實現類對象*/
ReflectProxy reflectProxy =
(ReflectProxy)Proxy.newProxyInstance(ReflectProxy.class.getClassLoader(), new Class[]{ReflectProxy.class}, new InvocationHandlerTest());
System.out.println(reflectProxy.fun(100));
reflectProxy.run();
try
{
/*通過Proxy.getProxyClass方法,創建ReflectProxy接口的實現類的Class對象*/
Class<?> cls = Proxy.getProxyClass(ReflectProxy.class.getClassLoader(), new Class[]{ReflectProxy.class});
/*通過Class對象獲取構造器,參數必須是InvocationHandler.class*/
Constructor<?> constructor = cls.getConstructor(new Class[]{InvocationHandler.class});
/*通過構造器創建ReflectProxy接口的實現類對象*/
ReflectProxy reflectProxy1 = (ReflectProxy)constructor.newInstance(new Object[]{new InvocationHandlerTest()});
System.out.println(reflectProxy1.fun(500));
reflectProxy1.run();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
interface ReflectProxy
{
int fun(int i);
void run();
}
/*實現InvocationHandler接口中的invoke方法,用於代理ReflectProxy接口中的fun方法和run方法
*invoke的參數說明:
*proxy爲動態代理對象
*method當前調用的方法
*args當前調用方法的入參
*/
class InvocationHandlerTest implements InvocationHandler
{
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
if ("fun".equals(method.getName()))
{
System.out.println("do fun() arg is "+args[0]);
return args[0];
}
if ("run".equals(method.getName()))
{
System.out.println("do run()");
}
return null;
}
}
結果輸出:
動態代理原理:Proxy.getProxyClass通過反射獲取到接口中的所有抽象方法,再通過ProxyGenerator.generateProxyClass()方法生成一個接口的實現類的字節碼文件(這個實現類中的有一個入參爲InvocationHandler的構造器,並將所有方法的實現都轉爲InvocationHandler的invoke方法進行代理!),最終返回這個接口實現類的Class對象!
4. 基於動態代理實現AOP:
可以通過Java對接口的動態代理實現對特定方法增加切面,實現面向切面編程!示例如下:
public class ReflectProxyTest
{
public static void main(String[] args)
{
/*通過Proxy.newProxyInstance方法,創建ReflectProxy接口的實現類對象*/
ReflectProxy reflectProxy =
(ReflectProxy)Proxy.newProxyInstance(ReflectProxy.class.getClassLoader(), new Class[]{ReflectProxy.class}, new InvocationHandlerTest(new ReflectProxyTemp1()));
System.out.println(reflectProxy.fun(100));
reflectProxy.run();
}
}
interface ReflectProxy
{
int fun(int i);
void run();
}
/*通過實現InvocationHandler接口,來實現對ReflectProxyTemp1類中方法增加切面*/
class InvocationHandlerTest implements InvocationHandler
{
private Object tager;
public InvocationHandlerTest(Object tager)
{
this.tager = tager;
}
private void aopFun1()
{
System.out.println("aopFun1()");
}
private void aopFun2()
{
System.out.println("aopFun2()");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
/*增加Aop切面1*/
this.aopFun1();
/*通過tager將原始實現傳入InvocationHandler實現類*/
method.invoke(this.tager, args);
/*增加Aop切面2*/
this.aopFun2();
if ((null != args) && (0 != args.length))
{
return args[0];
}
return null;
}
}
/*原始類型,期望在ReflectProxyTemp1類的fun()方法和run()方法上增加切面*/
class ReflectProxyTemp1 implements ReflectProxy
{
@Override
public int fun(int i)
{
System.out.println("ReflectProxyTemp1 fun() i is " + i);
return 0;
}
@Override
public void run()
{
System.out.println("ReflectProxyTemp1 run()");
}
}
結果輸出: