1. 程式人生 > >Java原始碼解析(2) —— Class(1)

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
註釋 : null1:如果是以下形式
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> {