Java原始碼解析(2) —— Class(1)
Class —— 反射基石
Java基本類之一,反射機制的基礎。其意義為:類的抽象,即對“類”做描述:比如類有修飾、欄位、方法等屬性,有獲得該類的所有方法、所有公有方法等方法。同時,Class也是Java型別中最重要的一種,表示原始型別(引用型別)及基本型別。
宣告
1.Class的原始碼太長,這裡分4部分解析,一些方法的實現原始碼較長,這裡就沒有貼出來了,我會著重將敘述其作用,至於其實現邏輯,以本人現有水平估計也很難一一講解清晰,大家姑且看之,若其中有錯誤地方或未講解明白的可留言探討。
2.閱讀該文前,若對反射和泛型知識有一定基礎最好。
原始碼
public final
class Class<T> implements java.io.Serializable,
java.lang.reflect.GenericDeclaration,
java.lang.reflect.Type,
java.lang.reflect.AnnotatedElement {
private static final int ANNOTATION= 0x00002000;//註釋型別
private static final int ENUM = 0x00004000;//列舉型別
private static final int SYNTHETIC = 0x00001000;//合成型別,注0
//列舉是一種類(class),註釋是一種介面(interface)
private transient String name;//全限定名(包+類名)
private native String getName0();//本地方法獲取name屬性
//註冊本地方法
private static native void registerNatives();
static {
registerNatives();
}
private Class() {}//唯一私有構造方法,說明Class不可由使用者構造例項
public String toString() {
//這裡重寫toString,只區別了介面和Class
return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+ getName();
}
//通過類全限定名獲得該類(或介面)的Class物件(載入該類)
@CallerSensitive //注1
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
//initialize : 是否立即初始化該類,注2
//loader : 使用指定的類載入器載入
}
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
//反射獲得該類例項物件
@CallerSensitive
public T newInstance()
throws InstantiationException, IllegalAccessException
{
//JDK明言:本方法在當前Java記憶體模型下不一定是正確的
//反射獲取該類例項物件,例項化物件不是通過new指令,而是直接
//通過本地方法獲取類的公有構造方法(無參),然後通過Constructor的
//newInstance();方法例項化物件
//這個過程還要檢查是否有許可權反射例項化該物件
}
//快取上面方法已獲取的公有構造方法,供下次使用
private volatile transient Constructor<T> cachedConstructor;
//快取呼叫本方法的最初物件的類Class物件,供安全檢查使用,見注1
private volatile transient Class<?> newInstanceCallerCache;
//判斷obj物件是否是該Class的例項
public native boolean isInstance(Object obj);
//判斷cls是否是呼叫者同一型別或其子類型別
public native boolean isAssignableFrom(Class<?> cls);
//判斷該Class是否是介面型別
public native boolean isInterface();
//判斷該Class是否是陣列型別
public native boolean isArray();
//判斷該Class是否是基本型別,注3(八大基本型別+一特殊基本型別)
public native boolean isPrimitive();
//判斷該Class是否是註釋型別
public boolean isAnnotation() {
return (getModifiers() & ANNOTATION) != 0;
}
//判斷該Class是否是合成型別
public boolean isSynthetic() {
return (getModifiers() & SYNTHETIC) != 0;
}
public String getName() {
String name = this.name;
if (name == null)
this.name = name = getName0();//通過本地方法獲取全路徑類名
return name;
}
//獲取載入該類的類載入器
@CallerSensitive
public ClassLoader getClassLoader() {
ClassLoader cl = getClassLoader0();
if (cl == null)
return null;
SecurityManager sm = System.getSecurityManager();//注5
if (sm != null) {
ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
}
return cl;
}
native ClassLoader getClassLoader0();
//返回該類中變數欄位的型別變數陣列,按宣告順序排序,注4
public TypeVariable<Class<T>>[] getTypeParameters() {
if (getGenericSignature() != null)
return (TypeVariable<Class<T>>[])getGenericInfo().getTypeParameters();
else
return (TypeVariable<Class<T>>[])new TypeVariable<?>[0];
}
//獲得該類的直接父類的Class物件,如果該類是介面,則返回null
public native Class<? super T> getSuperclass();
//返回帶引數化型別的直接父類的型別
public Type getGenericSuperclass() {}
//獲取該類的包路徑
public Package getPackage() {
return Package.getPackage(this);
}
//獲取該類直接實現的所有介面
public native Class<?>[] getInterfaces();
//獲取所有介面,同上面的不同之處在於,若超介面是引數化型別(泛型)則返回的是其實際型別
public Type[] getGenericInterfaces() {
if (getGenericSignature() != null)
return getGenericInfo().getSuperInterfaces();
else
return getInterfaces();
}
/**返回陣列型別,若該類不是陣列,返回null
* 如:A[] a = new A[];
* a.getClass().getComponentType()返回的是A型別(全路徑名)
*/
public native Class<?> getComponentType();
//返回這個類的修飾符的對應的int值,二者可通過Modifier.toString()轉換
public native int getModifiers();
//獲取該類的所有簽名(標記)列表
public native Object[] getSigners();
//設定該類的簽名,注意方法修飾是預設,所以只有同包下類可用
native void setSigners(Object[] signers);
/**
* 以上兩個方法不是很懂具體用來幹什麼的,估計是和安全檢查什麼有關,因為
* setSigners()是預設修飾,只能同包下訪問(這就是說,使用者是用不了的)
*/
}
注0:合成型別,參考:synthetic Java合成型別
注1:@CallerSensitive註解,參考:JVM註解@CallSensitive(HEL_WOR)
注2:類的初始化
forName()方法預設是初始化類,不需要載入的的時候同時初始化類,需用forName的過載函式。類的載入、初始化可參考:Java類的載入
注3:Java基本資料型別
除了8大基本型別,還有void,詳見:Java變數資料型別
注4:Java型別,詳見:Type Java型別。
注5:關於Java安全策略之安全管理器,現可以參考:java安全沙箱(四)(xionghuiCoder)
概述
Class類,表示Java的基礎型別(類+基本型別),是對Java類的抽象,描述的是類的資訊,包括類的修飾符(public/private/protect/default/static/final等)、類的型別(一般類、列舉、註釋、介面、陣列等)、類的構造器、類的欄位、類的方法等資訊。所以在看待Class相關問題的時候應該從所有類的共性這個角度去看。注意,這裡的類不是平常我們說的狹義上的類(class),而是廣義上,包括了像介面、註釋、陣列等型別的類,下面若不特殊宣告,類代表著廣義上的類。
每一個類在JVM記憶體中,有一個唯一的對應的Class物件,這個物件有著該類的描述資訊,所以執行時可以通過該Class類物件進行相應的操作,這就是Java的反射了。(Java基本型別也對應一個Class物件)
//獲得Class物件的方法
//1.通過 型別.class 獲得,適用於所有型別
Class str = String.class;
Class i = int.class;
Class d = Double[].class;
//2.通過 Object的getClass() 方法獲得,適用於所有非基本型別
A a = new A(); Class ac = a.getClass();
//3.通過 Class.forName(String name) 方法獲得
Class ac1 = Class.forName("com.fcc.test.A");//注意要用全限定名
原始碼詳解
1.forName
靜態方法,通過類的全限定名載入類,返回該類的Class物件,forName有兩個過載,forName(String)和forName(String, boolean, ClassLoader),其中,第一個引數是類的全限定名,第二個引數是指載入該類的後是否初始化該類,預設是載入後並初始化該類,最後一個引數是指使用哪個類載入器載入該類,預設是使用當前類的類載入器載入該類。
2.newInstance
建立該Class物件對應的物件例項,只有當類具有公有的無參構造方法才能成功,否則拋異常,關於newInstance詳見:newInstance和new(編輯中)。
3.getClassLoader
獲得載入該類的類載入器,在本JVM(Oracle HotSopt),當本類的類載入器是引導類載入器(bootStrap)則返回的是null。(類的載入見上面注2。)
4.getTypeParameters
返回該類中宣告(定義)的類變數陣列,例如:
//關於TypeVariable詳見注3
public class Main<K, V> {
public static void main(String[] args) throws Exception
{
Class cl = Main.class;
TypeVariable[] types = cl.getTypeParameters();
for(TypeVariable type : types){
System.out.println(type.getName());
}
}
}
K
V
5.getSuperclass
獲得該Class的直接父類對應的Class物件,如果該Class是基本型別(包括void,注意是小寫的關鍵字void,不是大寫的類Void)、介面、註釋,則返回null。
Class c0 = Main.class;//類,返回直接父類,泛型當做普通類處理
Class c1 = EnumA.class;//列舉型別,預設繼承Enum類
Class c2 = int.class;//基本型別返回null
Class c3 = int[].class;//陣列統一返回 class Object
Class c4 = InterfaceB.class;//介面也是返回null
Class c5 = Deprecated.class;//註釋型別也返回null,c5.isInterface() 為true
System.out.println("類 : " + c0.getSuperclass());
System.out.println("列舉 : " + c1.getSuperclass());
System.out.println("基本型別 : " + c2.getSuperclass());
System.out.println("陣列 : " + c3.getSuperclass());
System.out.println("介面 : " + c4.getSuperclass());
System.out.println("註釋 : " + c5.getSuperclass());
//輸出結果
類 : class java.lang.Object
列舉 : class java.lang.Enum
基本型別 : null
陣列 : class java.lang.Object
介面 : null
註釋 : null
6.getGenericSuperclass
獲得直接父類的型別,可以理解為在5的基礎上,如果其是泛型,再獲得其型別原型(但需要繼承時顯式表示)。
public class Main<K, V> {
public static void main(String[] args) throws Exception
{
Class c0 = ClassA.class;
Class c1 = EnumA.class;//列舉型別,預設繼承Enum類
Class c2 = int.class;//基本型別返回null
Class c3 = ClassA[].class;//陣列統一返回 class Object
Class c4 = InterfaceB.class;//介面也是返回null
Class c5 = Deprecated.class;//註釋型別也返回null
System.out.println("類 : " + c0.getGenericSuperclass());
System.out.println("列舉 : " + c1.getGenericSuperclass());
System.out.println("基本型別 : " + c2.getGenericSuperclass());
System.out.println("陣列 : " + c3.getGenericSuperclass());
System.out.println("介面 : " + c4.getGenericSuperclass());
System.out.println("註釋 : " + c5.getGenericSuperclass());
System.out.println(c2.isInterface());
}
}
class ClassA<K,V> extends Main<K,V>{}//注1
//輸出結果
類 : com.fcc.test.Main<K, V>
列舉 : java.lang.Enum<com.fcc.test.EnumA>
基本型別 : null
陣列 : class java.lang.Object
介面 : null
註釋 : null
注1:如果是以下形式
class ClassA extends Main{}
則輸出為:類 : com.fcc.test.Main
7.getInterfaces
8.getGenericInterfaces
getInterfaces/getGenericInterfaces這一對同getSuperclass/getGenericSuperclass類似,getInterfaces/getGenericInterfaces前者是獲得該類直接實現的所有介面(不包括介面的父介面,也不包括父類實現的介面),後者是,如果介面是泛型,還原泛型的原型(但需要實現時顯式表示,這一點同getGenericSuperclass類似)。不過不管是哪一對,要注意,返回值型別的不同。
Class c0 = ClassB.class;
Class[] ifaces = c0.getInterfaces();
for(Class c : ifaces){
System.out.println(c);
}
Type[] ifaces1 = c0.getGenericInterfaces();
for(Type c : ifaces1){
System.out.println(c);
}
class ClassB<E> extends ClassA implements InterfaceB<E>{}
//輸出結果
interface com.fcc.test.InterfaceB
com.fcc.test.InterfaceB<E>
相關推薦
Java原始碼解析(2) —— Class(1)
Class —— 反射基石 Java基本類之一,反射機制的基礎。其意義為:類的抽象,即對“類”做描述:比如類有修飾、欄位、方法等屬性,有獲得該類的所有方法、所有公有方法等方法。同時,Class也是Java型別中最重要的一種,表示原始型別(引用型別)及基本型
Java原始碼解析(5) —— Class(4)
Class最後一部分原始碼,這一部分大都是private方法、屬性、類,都是Class本身各種方法的實現細節,涉及到了很多Class的實現原理,較為深奧,網上能找到的資料也比較少,目前只懂皮毛,僅供參考,所以,我這一部分說的可能是不正確的,需要抱著懷疑的態度看待
java之ArrayList初始容量原始碼解析【jdk 1.8】
ArrayList解析 繼承的類和實現的介面 public class ArrayList<E>extends AbstractList<E>implements List<
JAVA常用集合框架原始碼解析(基於1.8)開題篇
倪升武的部落格中有一個小專題,讀完之後,發現博主的分析基本是基於JAVA1.7的,這裡我基於JAVA1.8給出一些新的解讀。但是對於JAVA1.8新增的一些新特性可能不太會作過多的分析(畢竟本人目前水平有限,且本部落格的寫作初衷也是以基礎學習為主),在徹底淺讀完
JDK核心JAVA原始碼解析(1)
想寫這個系列很久了,對自己也是個總結與提高。原來在學JAVA時,那些JAVA入門書籍會告訴你一些規律還有法則,但是用的時候我們一般很難想起來,因為我們用的少並且不知道為什麼。知其所以然方能印象深刻並學以致用。 首先我們從所有類的父類Object開始: 1
Yii1.1原始碼解析2之根據路由查詢控制器
檔案路徑/framework/web/CWebApplication.php /** * Creates a controller instance based on a route. * The route should contain the controlle
Java原始碼解析(7) —— ClassLoader(2)
ClassLoader原始碼解析續 這一部分是ClassLoader核心部分,載入給定的資料成對應的類物件。 /** * 由虛擬機器呼叫,這是一個private方法,但我在ClassLoader原始碼中並未看到有地方呼叫 * 看名字及原始碼說明,是由虛擬
Java原始碼解析(1) —— Object
Java基類Object java.lang.Object,Java所有類的父類,在你編寫一個類的時候,若無指定父類(沒有顯式extends一個父類)編譯器(一般編譯器完成該步驟)會預設的新增Object為該類的父類(可以將該類反編譯看其位元組碼,不過貌似
Java編譯(二) Java前端編譯:Java原始碼編譯成Class檔案的過程
Java編譯(二)Java前端編譯: Java原始碼編譯成Class檔案的過程 在上篇文章《Java三種編譯方式:前端編
10.1java原始碼解析-Integer (1)
1類的宣告 public final class Integer extends Number implements Comparable<Integer> 繼承 Number 實現 Comparable<Integer> 可以比較大小
11 java原始碼解析-Thread(草稿)
1類的宣告 public class Thread implements Runnable 實現了Runnable介面 在程式開發中只要是多執行緒肯定永遠以實現Runnable介面為主。 1.1Runnable 說明 public interface Run
Java原始碼解析系列(二)ArrayList原始碼解析
備註:以下都是基於JDK8 原始碼分析 ArrayList簡介 ArrayList 是一個數組佇列,相當於 動態陣列。與Java中的陣列相比,它的容量能動態增長。它繼承於AbstractList,實現了List, RandomAccess, Clonea
Java原始碼解析ArrayList
本文基於jdk1.8來分析ArrayList的原始碼 首先是主要的成員變數。 /** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10; /
java原始碼解析--Map
Map集合 An object that maps keys to values. A map cannot contain duplicate keys; each key can map to
java原始碼解析S
Set A collection that contains no duplicate elements. More formally, sets contain no pair of elemen
Java原始碼解析CopyOnWriteArrayList
本文基於jdk1.8進行分析。 ArrayList和HashMap是我們經常使用的集合,它們不是執行緒安全的。我們一般都知道HashMap的執行緒安全版本為ConcurrentHashMap,那麼ArrayList有沒有類似的執行緒安全的版本呢?還真有,它就是CopyOnWriteArrayLi
Java原始碼解析阻塞佇列ArrayBlockingQueue功能簡介
本文基於jdk1.8進行分析。 阻塞佇列是java開發時常用的一個數據結構。首先看一下阻塞佇列的作用是什麼。阻塞佇列的作用,從原始碼中類的註釋中來了解,是最清晰準確的。如下圖。 ArrayBlockingQueue是一個用陣列實現的有界阻塞佇列。提供FIFO的功能。佇列頭上的元素是在佇列中呆
Java原始碼解析之可重入鎖ReentrantLock(二)
上文接Java原始碼解析之可重入鎖ReentrantLock(一)。 接下來是tryLock方法。程式碼如下。從註釋中我們可以理解到,只有當呼叫tryLock時鎖沒有被別的執行緒佔用,tryLock才會獲取鎖。如果鎖沒有被另一個執行緒佔用,那麼就獲取鎖,並立刻返回true,並把鎖計數設定為1.
Java原始碼解析之可重入鎖ReentrantLock(一)
本文基於jdk1.8進行分析。 ReentrantLock是一個可重入鎖,在ConcurrentHashMap中使用了ReentrantLock。 首先看一下原始碼中對ReentrantLock的介紹。如下圖。ReentrantLock是一個可重入的排他鎖,它和synchronized的方法
Java原始碼解析LinkedList
本文基於jdk1.8進行分析。 LinkedList和ArrayList都是常用的java集合。ArrayList是陣列,Linkedlist是連結串列,是雙向連結串列。它的節點的資料結構如下。 private static class Node<E> {