1. 程式人生 > >關於getClass(),Object.class,getClassLoader的理解

關於getClass(),Object.class,getClassLoader的理解

1、對Class類的理解:Class類包含了類的資訊,如構造方法、方法、屬性,可用於反射。以下是所有方法

2、獲取Class類物件的集中方法:

Test test = new Test();

(1).test.getClass();

     在執行時確定,所以執行例項才是該類物件。super.getClass()不能獲得父類的類物件,仍然是當前類物件。

     獲得父類類物件: test.getClass().getSuperclass()


class Father{
    public void showName()
    {
         System.out.println("Father...");
    }
}

class Child extends Father{
    public void showName()
    {
         System.out.println("children");
    }
}

Father father = new Child();
System.out.println(Father.class);      結果是 Father
System.out.println(father.getClass()); 結果是 Child

(2).Test.class;

     在編譯時確定,返回當前類的類物件例項。

     獲得父類類物件: Test.class.getSuperclass()

(3).Class.forName("類路徑");

     通過靜態方法獲取類物件,Class.forName("com.wan.Test");

 

在執行期間,如果我們要產生某個類的物件,Java虛擬機器(JVM)會檢查該型別的Class物件是否已被載入。如果沒有被載入,JVM會根據類的名稱找到.class檔案並載入它。一旦某個型別的Class物件已被載入到記憶體,就可以用它來產生該型別的所有物件 

普通類為什麼不能用static修飾?

 

3、classLoader相關理解

請在Eclipse中新建如下類,並執行它:

複製程式碼

package java.lang;

public class Long {
    public static void main(String[] args) {
        System.out.println("Hi, i am here");
    }
}

複製程式碼

你能猜到它的執行如果嗎? 不錯,就是如下這個樣子!

錯誤: 在類 java.lang.Long 中找不到 main 方法, 請將 main 方法定義為:
public static void main(String[] args)
否則 JavaFX 應用程式類必須擴充套件javafx.application.Application

 





為什麼呢,明明我在Long方法類中定義了main方法,為什麼說main方法沒有定義呢?

本文將解決以上問題出現的原因。

二、ClassLoader的作用

我們都知道java程式寫好以後是以.java(文字檔案)的檔案存在磁碟上,然後,我們通過(bin/javac.exe)編譯命令把.java檔案編譯成.class檔案(位元組碼檔案),並存在磁碟上。但是程式要執行,首先一定要把.class檔案載入到JVM記憶體中才能使用的,我們所講的classLoader,就是負責把磁碟上的.class檔案載入到JVM記憶體中,如下圖所示:

你可以認為每一個Class物件擁有磁碟上的那個.class位元組碼內容,每一個class物件都有一個getClassLoader()方法,得到是誰把我從.class檔案載入到記憶體中變成Class物件的。

三、ClassLoader層次結構

請執行如下程式:

複製程式碼

public class Test {
    public static void main(String[] args) {
         ClassLoader classLoader = Test.class.getClassLoader();
         System.out.println(classLoader);
         
         ClassLoader classLoader1 = classLoader.getParent();
         System.out.println(classLoader1);
         
         ClassLoader classLoader2 = classLoader1.getParent();
         System.out.println(classLoader2); 
     }
 }

複製程式碼

它的輸出是:

[email protected]
[email protected]
null

得到了 classLoader2就是null值了。這裡其實有三個類載入器:

(1): 根類載入器(null)

它是由原生代碼(c/c++)實現的,你根本拿不到他的引用,但是他實際存在,並且載入一些重要的類,它載入(%JAVA_HOME%\jre\lib),如rt.jar(runtime)、i18n.jar等,這些是Java的核心類。

(2): 擴充套件類載入器(ExtClassLoader)

雖說能拿到,但是我們在實踐中很少用到它,它主要載入擴充套件目錄下的jar包, %JAVA_HOME%\lib\ext

(3): 應用類載入器(AppClassLoader)

它主要載入我們應用程式中的類,如Test,或者用到的第三方包,如jdbc驅動包等。

這裡的父類載入器與類中繼承概念要區分,它們在class定義上是沒有父子關係的。

四、Class載入時呼叫類載入器的順序

當一個類要被載入時,有一個啟動類載入器和實際類載入器的概念,這個概念請看如下分析

如上面的Test.class要進行載入時,它將會啟動應用類載入器進行載入Test類,但是這個應用類載入器不會真正去載入他,而是會呼叫看是否有父載入器,結果有,是擴充套件類載入器,擴充套件類載入器也不會直接去載入,它看自己是否有父載入器沒,結果它還是有的,是根類載入器。

所以這個時候根類載入器就去載入這個類,可在%JAVA_HOME%\jre\lib下,它找不到com.Test這個類,所以他告訴他的子類載入器,我找不到,你去載入吧,子類擴充套件類載入器去%JAVA_HOME%\lib\ext去找,也找不著,它告訴它的子類載入器 AppClassLoader,我找不到這個類,你去載入吧,結果AppClassLoader找到了,就加到記憶體中,並生成Class物件。
這個時間時候啟動類載入器(應用類載入器)和實際類載入器(應用類載入器)是同一個.

這就是Java中著名的委託載入機制,看如下圖:

我們再來看一下 java.lang.Long的載入,按上面分析,應該是由根類載入器載入得到的,此時啟動類載入器是應用類載入器,但實際類載入器是根類載入器。

所以回到我們最開始那個問題,沒有main方法是因為執行的根本不是我們自己寫的類,執行的是java核心中的那個Long類,當然沒有main方法了。 這樣就防止我們應用中寫的類覆蓋掉java核心類。