java基礎(chǔ)專欄今天介紹超詳細(xì)的JVM反射原理技術(shù)點(diǎn)總結(jié)哦。
反射定義
1,JAVA反射機(jī)制是在運(yùn)行狀態(tài)中
#對於任意一個類,都能夠知道這個類別的所有屬性和方法;
對於任意一個對象,都能夠調(diào)用它的任意一個方法和屬性;
這種動態(tài)獲取的資訊以及動態(tài)呼叫物件的方法的功能稱為java語言的反射機(jī)制。
反射提供的功能:
- 在執(zhí)行階段判斷任意一個物件所屬的類別
- 在執(zhí)行時建構(gòu)任意一個類別的物件
- 在執(zhí)行時判斷任何一個類別所具有的成員變數(shù)和方法
- 在執(zhí)行階段呼叫任何一個物件的方法
? ??#(如果屬性是private,則正常情況下方是不允許外界操作屬性值,這裡可以用Field類別的setAccessible(true)方法,暫時開啟操作的權(quán)限)
反射的使用場景
- ##Java編碼時知道類別和物件的具體訊息,此時直接對類別和物件進(jìn)行操作即可,無需反射
- 如果編碼時不知道類別或物件的具體訊息,此時應(yīng)該使用反射來實(shí)現(xiàn)
Class.forName("com.my.reflectTest").newInstance()復(fù)制代碼1. 反射取得類別實(shí)例Class.forName("xxx");# 先調(diào)用了java.lang.Class 的靜態(tài)方法,取得類別資訊! 注意:forName()反射獲取類別信息,並沒有將實(shí)作留給了java,而是交給了jvm去加載! ? ? ? ? ? 主要是先取得 ClassLoader, 然後呼叫 native 方法,取得信息,載入類別則是回呼 入?yún)lassLoader 進(jìn)類別載入!
@CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { // 先通過反射,獲取調(diào)用進(jìn)來的類信息,從而獲取當(dāng)前的 classLoader Class<?> caller = Reflection.getCallerClass(); // 調(diào)用native方法進(jìn)行獲取class信息 return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }復(fù)制代碼2.?java.lang.ClassLoader-----loadClass()
// java.lang.ClassLoader
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 先獲取鎖
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
// 如果已經(jīng)加載了的話,就不用再加載了
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
// 雙親委托加載
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
// 父類沒有加載到時,再自己加載
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
protected Object getClassLoadingLock(String className) {
Object lock = this;
if (parallelLockMap != null) {
// 使用 ConcurrentHashMap來保存鎖
Object newLock = new Object();
lock = parallelLockMap.putIfAbsent(className, newLock);
if (lock == null) {
lock = newLock;
}
}
return lock;
}
protected final Class<?> findLoadedClass(String name) {
if (!checkName(name))
return null;
return findLoadedClass0(name);
}復(fù)制代碼
3. newInstance()?newInstance() 其實(shí)相當(dāng)于調(diào)用類的無參構(gòu)造函數(shù),主要做了三件事復(fù)制代碼
- #權(quán)限偵測,如果不透過直接拋出例外;
- 尋找無參構(gòu)器,並將其快取起來; ##呼叫特定方法的無參建構(gòu)方法,產(chǎn)生實(shí)例並回傳;
// 首先肯定是 Class.newInstance @CallerSensitive public T newInstance() throws InstantiationException, IllegalAccessException { if (System.getSecurityManager() != null) { checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false); } // NOTE: the following code may not be strictly correct under // the current Java memory model. // Constructor lookup // newInstance() 其實(shí)相當(dāng)于調(diào)用類的無參構(gòu)造函數(shù),所以,首先要找到其無參構(gòu)造器 if (cachedConstructor == null) { if (this == Class.class) { // 不允許調(diào)用 Class 的 newInstance() 方法 throw new IllegalAccessException( "Can not call newInstance() on the Class for java.lang.Class" ); } try { // 獲取無參構(gòu)造器 Class<?>[] empty = {}; final Constructor<T> c = getConstructor0(empty, Member.DECLARED); // Disable accessibility checks on the constructor // since we have to do the security check here anyway // (the stack depth is wrong for the Constructor's // security check to work) java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { c.setAccessible(true); return null; } }); cachedConstructor = c; } catch (NoSuchMethodException e) { throw (InstantiationException) new InstantiationException(getName()).initCause(e); } } Constructor<T> tmpConstructor = cachedConstructor; // Security check (same as in java.lang.reflect.Constructor) int modifiers = tmpConstructor.getModifiers(); if (!Reflection.quickCheckMemberAccess(this, modifiers)) { Class<?> caller = Reflection.getCallerClass(); if (newInstanceCallerCache != caller) { Reflection.ensureMemberAccess(caller, this, null, modifiers); newInstanceCallerCache = caller; } } // Run constructor try { // 調(diào)用無參構(gòu)造器 return tmpConstructor.newInstance((Object[])null); } catch (InvocationTargetException e) { Unsafe.getUnsafe().throwException(e.getTargetException()); // Not reached return null; } }復(fù)制代碼
4. getConstructor0() 為取得符合的建構(gòu)子器;分三步驟:
1. 先取得所有的constructors, 然後透過進(jìn)行參數(shù)類型比較; 2. 找到匹配後,透過 ReflectionFactory copy一份constructor返回; 3. 否則拋出 NoSuchMethodException;
private Constructor<T> getConstructor0(Class<?>[] parameterTypes, int which) throws NoSuchMethodException { // 獲取所有構(gòu)造器 Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC)); for (Constructor<T> constructor : constructors) { if (arrayContentsEq(parameterTypes, constructor.getParameterTypes())) { return getReflectionFactory().copyConstructor(constructor); } } throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes)); }復(fù)制代碼
5.?privateGetDeclaredConstructors(), 取得所有的建構(gòu)器主要步驟;
1. 先嘗試從快取中取得; 2. 如果快取沒有,則從jvm中重新獲取,並存入緩存,快取使用軟引用進(jìn)行保存,保證記憶體可用;
// 獲取當(dāng)前類所有的構(gòu)造方法,通過jvm或者緩存 // Returns an array of "root" constructors. These Constructor // objects must NOT be propagated to the outside world, but must // instead be copied via ReflectionFactory.copyConstructor. private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) { checkInitted(); Constructor<T>[] res; // 調(diào)用 reflectionData(), 獲取保存的信息,使用軟引用保存,從而使內(nèi)存不夠可以回收 ReflectionData<T> rd = reflectionData(); if (rd != null) { res = publicOnly ? rd.publicConstructors : rd.declaredConstructors; // 存在緩存,則直接返回 if (res != null) return res; } // No cached value available; request value from VM if (isInterface()) { @SuppressWarnings("unchecked") Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0]; res = temporaryRes; } else { // 使用native方法從jvm獲取構(gòu)造器 res = getDeclaredConstructors0(publicOnly); } if (rd != null) { // 最后,將從jvm中讀取的內(nèi)容,存入緩存 if (publicOnly) { rd.publicConstructors = res; } else { rd.declaredConstructors = res; } } return res; } // Lazily create and cache ReflectionData private ReflectionData<T> reflectionData() { SoftReference<ReflectionData<T>> reflectionData = this.reflectionData; int classRedefinedCount = this.classRedefinedCount; ReflectionData<T> rd; if (useCaches && reflectionData != null && (rd = reflectionData.get()) != null && rd.redefinedCount == classRedefinedCount) { return rd; } // else no SoftReference or cleared SoftReference or stale ReflectionData // -> create and replace new instance return newReflectionData(reflectionData, classRedefinedCount); } // 新創(chuàng)建緩存,保存反射信息 private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData, int classRedefinedCount) { if (!useCaches) return null; // 使用cas保證更新的線程安全性,所以反射是保證線程安全的 while (true) { ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount); // try to CAS it... if (Atomic.casReflectionData(this, oldReflectionData, new SoftReference<>(rd))) { return rd; } // 先使用CAS更新,如果更新成功,則立即返回,否則測查當(dāng)前已被其他線程更新的情況,如果和自己想要更新的狀態(tài)一致,則也算是成功了 oldReflectionData = this.reflectionData; classRedefinedCount = this.classRedefinedCount; if (oldReflectionData != null && (rd = oldReflectionData.get()) != null && rd.redefinedCount == classRedefinedCount) { return rd; } } }復(fù)制代碼
另外,使用relactionData() 進(jìn)行快取保存;ReflectionData 的資料結(jié)構(gòu)如下!
// reflection data that might get invalidated when JVM TI RedefineClasses() is called private static class ReflectionData<T> { volatile Field[] declaredFields; volatile Field[] publicFields; volatile Method[] declaredMethods; volatile Method[] publicMethods; volatile Constructor<T>[] declaredConstructors; volatile Constructor<T>[] publicConstructors; // Intermediate results for getFields and getMethods volatile Field[] declaredPublicFields; volatile Method[] declaredPublicMethods; volatile Class<?>[] interfaces; // Value of classRedefinedCount when we created this ReflectionData instance final int redefinedCount; ReflectionData(int redefinedCount) { this.redefinedCount = redefinedCount; } }復(fù)制代碼
6.透過上面,取得到 Constructor 了!接下來就只要呼叫其對應(yīng)建構(gòu)器的 newInstance(),也就是回傳實(shí)例了!
// return tmpConstructor.newInstance((Object[])null); // java.lang.reflect.Constructor @CallerSensitive public T newInstance(Object ... initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, null, modifiers); } } if ((clazz.getModifiers() & Modifier.ENUM) != 0) throw new IllegalArgumentException("Cannot reflectively create enum objects"); ConstructorAccessor ca = constructorAccessor; // read volatile if (ca == null) { ca = acquireConstructorAccessor(); } @SuppressWarnings("unchecked") T inst = (T) ca.newInstance(initargs); return inst; } // sun.reflect.DelegatingConstructorAccessorImpl public Object newInstance(Object[] args) throws InstantiationException, IllegalArgumentException, InvocationTargetException { return delegate.newInstance(args); } // sun.reflect.NativeConstructorAccessorImpl public Object newInstance(Object[] args) throws InstantiationException, IllegalArgumentException, InvocationTargetException { // We can't inflate a constructor belonging to a vm-anonymous class // because that kind of class can't be referred to by name, hence can't // be found from the generated bytecode. if (++numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) { ConstructorAccessorImpl acc = (ConstructorAccessorImpl) new MethodAccessorGenerator(). generateConstructor(c.getDeclaringClass(), c.getParameterTypes(), c.getExceptionTypes(), c.getModifiers()); parent.setDelegate(acc); } // 調(diào)用native方法,進(jìn)行調(diào)用 constructor return newInstance0(c, args); }復(fù)制代碼
傳回建構(gòu)器的實(shí)例後,可以根據(jù)外部進(jìn)行進(jìn)行型別轉(zhuǎn)換,從而使用介面或方法進(jìn)行呼叫實(shí)例功能了。
相關(guān)免費(fèi)學(xué)習(xí)推薦:java基礎(chǔ)
以上是超詳細(xì)的JVM反射原理技術(shù)點(diǎn)總結(jié)哦~的詳細(xì)內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)