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


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

2、獲取Class類對象的幾種方法:

Test test = new Test();

(1).test.getClass();

     在運行時確定,所以運行實例才是該類對象。super.getClass()不能獲得父類的類對象,仍然是當前類對象。

     獲得父類類對象: test.getClass().getSuperclass()

  1.  
     
  2.  
    class Father{
  3.  
    public void showName()
  4.  
    {
  5.  
    System.out.println( "Father...");
  6.  
    }
  7.  
    }
  8.  
     
  9.  
    class Child extends Father{
  10.  
    public void showName()
  11.  
    {
  12.  
    System.out.println( "children");
  13.  
    }
  14.  
    }
  15.  
     
  16.  
    Father father = new Child();
  17.  
    System.out.println(Father.class); 結果是 Father
  18.  
    System.out.println(father.getClass()); 結果是 Child

(2).Test.class;

     在編譯時確定,返回當前類的類對象實例。不會加載靜態變量

     獲得父類類對象: Test.class.getSuperclass()

(3).Class.forName("類路徑");會加載靜態變量,比如jdbc驅動利用這個加載一些靜態屬性

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

 

在運行期間,如果我們要產生某個類的對象,Java虛擬機(JVM)會檢查該類型的Class對象是否已被加載。如果沒有被加載,JVM會根據類的名稱找到.class文件並加載它。一旦某個類型的Class對象已被加載到內存,就可以用它來產生該類型的所有對象 

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

講一下個人理解吧。static修飾的東西被我們成為類成員,它會隨着類的加載而加載,比如靜態代碼塊,靜態成員,靜態方法(這里只是加載,並沒有調用)等等,可以假象一下,如果把一個Class文件中的外部類設為static,那目的何在呢?難道讓這個類隨着應用的啟動而加載嗎?如果我在這次使用過程中根本沒有使用過這個類,那么是不是就會浪費內存。這樣來說設計不合理,總而言之,設計不合理的地方,Java是不會讓它存在的。
而為什么內部類可以使用static修飾呢,因為內部類算是類的成員了,如果我們沒有使用靜態來修飾,那么我們在創建內部類的時候就需要先有一個外部類的對象,如果我們一直在使用內部類,那么內存中就會一直存在外部類的引用,而我們有時候只需要使用內部類,不需要外部類,那么還是會浪費內存,甚至會造成內存溢出。使用static修飾內部類之后,內部類在創建對象時就不需要有外部類對象的引用了。
最終結論就是:static可以用來修飾內部類,但是不可以用來修飾外部類

3、classLoader相關理解

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

 

  1.  
    package java.lang;
  2.  
     
  3.  
    public class Long {
  4.  
    public static void main(String[] args) {
  5.  
    System.out.println( "Hi, i am here");
  6.  
    }
  7.  
    }

 

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

錯誤: 在類 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層次結構

請執行如下程序:

復制代碼

  1.  
    public class Test {
  2.  
    public static void main(String[] args) {
  3.  
    ClassLoader classLoader = Test.class.getClassLoader();
  4.  
    System.out.println(classLoader);
  5.  
     
  6.  
    ClassLoader classLoader1 = classLoader.getParent();
  7.  
    System.out.println(classLoader1);
  8.  
     
  9.  
    ClassLoader classLoader2 = classLoader1.getParent();
  10.  
    System.out.println(classLoader2);
  11.  
    }
  12.  
    }

復制代碼

它的輸出是:

sun.misc.Launcher$AppClassLoader@2a139a55
sun.misc.Launcher$ExtClassLoader@7852e922
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核心類。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM