已同步更新至我的blog:http://dxjia.cn/2015/08/java-class-object/java
類是面向對象編程語言的一個重要概念,它是對一項事物的抽象歸納,能夠包含該事物的一些屬性定義,以及操做屬性的方法。面向對象編程中,咱們都是以類來編碼。編程
簡單理解,就是new,就是對類的實例化,建立這個類對應的實際對象,類只是對事物的描述,而實例化就至關於爲這個描述新開闢了一塊內存,能夠改變這塊區域裏的各類屬性(成員變量),固然,也能夠實例化多塊區域,只是不一樣的對象而已。app
注意這裏C大寫了,與類概念區分開,在java裏,Class是一個實實在在的類,在包 java.lang 下,有這樣一個Class.java文件,它跟咱們本身定義的類同樣,是一個實實在在的類,Class對象就是這個Class類的實例了。在Java裏,全部的類的根源都是Object類,而Class也不例外,它是繼承自Object的一個特殊的類,它內部能夠記錄類的成員、接口等信息,也就是在Java裏,Class是一個用來表示類的類。(o(∩_∩)o 有點繞啊,抓住關鍵一點,Class是一個實實在在的類,能夠爲它建立實例,也就是本文後面提到的Class對象,也看叫作Class實例)。編程語言
java提供了下面幾種獲取到類的Class對象的方法:測試
1) 利用對象實例調用getClass()方法獲取該對象的Class實例;
2) 使用Class類的靜態方法forName("包名+類名"),用類的名字獲取一個Class實例編碼
3)運用 類名.class 的方式來獲取Class實例;spa
咱們知道java世界是運行在JVM之上的,咱們編寫的類代碼,在通過編譯器編譯以後,會爲每一個類生成對應的.class文件,這個就是JVM能夠加載執行的字節碼。運行時期間,當咱們須要實例化任何一個類時,JVM會首先嚐試看看在內存中是否有這個類,若是有,那麼會直接建立類實例;若是沒有,那麼就會根據類名去加載這個類,當加載一個類,或者當加載器(class loader)的defineClass()被JVM調用,便會爲這個類產生一個Class對象(一個Class類的實例),用來表達這個類,該類的全部實例都共同擁有着這個Class對象,並且是惟一的。code
在java裏,類只是信息描述的,寫明瞭有哪些內部屬性及接口,你能夠理解爲是定義了一套規則;而Class對象在java裏被用來對類的狀況進行表述的一個實例,也就是是類的實際表徵,能夠理解爲是對規則的圖表化,這樣JVM才能直觀的看懂,能夠看作是一個模版;而類的實例化對象,就是經過模版,開闢出的一塊內存進行實際的使用。對象
例子:blog
咱們經過一個例子來理解Class實例,爲了說明方便,咱們新建一個包名深點的類。
新建Name.java(固然,該文件要放在com\dxjia\sample的目錄下)
1 package com.dxjia.sample; 2 3 public class Name { 4 static int count = 0; 5 static { 6 count++; 7 System.out.println("Name Class Loaded! count = [" + count + "]" ); 8 } 9 10 public Name() { 11 System.out.println("Name Constructor called!"); 12 } 13 14 }
再在根目錄新建一個Test主類
1 import com.dxjia.sample.Name; 2 3 public class Test { 4 static { 5 Name mName; 6 System.out.println("Test Class loaded"); 7 } 8 9 public static void main(String[] args) { 10 System.out.println("entern Test main()"); 11 12 // Name.class 13 Class mClassPointClass; 14 // Class.forName("完整包名+類名") 15 Class mClassForName; 16 // new 對象後,對象.getClass() 17 Class mClassObjectPointClass1; 18 Class mClassObjectPointClass2; 19 20 try { 21 //測試 類名.class 22 mClassPointClass = Name.class; 23 System.out.println("mClassPointClass = " + mClassPointClass); 24 25 //測試Class.forName() 26 mClassForName = Class.forName("com.dxjia.sample.Name"); 27 System.out.println("mClassForName = " + mClassForName); 28 29 //測試Object.getClass() 30 Name name1 = new Name(); 31 mClassObjectPointClass1 = name1.getClass(); 32 System.out.println("mClassObjectPointClass1 = " + mClassObjectPointClass1); 33 } catch (ClassNotFoundException e) { 34 // TODO Auto-generated catch block 35 e.printStackTrace(); 36 return; 37 } 38 39 Name name2; 40 System.out.println("defined one Name object"); 41 name2 = new Name(); 42 System.out.println("Name object instance done!"); 43 44 mClassObjectPointClass2 = name2.getClass(); 45 46 if (mClassForName == mClassPointClass 47 && mClassPointClass == mClassObjectPointClass1 48 && mClassObjectPointClass1 == mClassObjectPointClass2) { 49 System.out.println("all the Class object equal..."); 50 } 51 } 52 }
分別對他們進行編譯:
1 javac com\dxjia\sample\Name.java 2 javac Test.java
執行:
1 java Test
代碼中使用了static靜態代碼塊來進行實驗,一個類的運行,JVM作會如下幾件事情 一、類裝載 二、連接 三、初始化 四、實例化;而初始化階段作的事情是初始化靜態變量和執行靜態方法等的工做,並且永遠只執行一次。
輸出結果:
Test Class loaded
entern Test main()
mClassPointClass = class com.dxjia.sample.Name
Name Class Loaded! count = [1]
mClassForName = class com.dxjia.sample.Name
Name Constructor called!
mClassObjectPointClass1 = class com.dxjia.sample.Name
defined one Name object
Name Constructor called!
Name object instance done!
all the Class object equal...
經過結果能夠看出在使用 類名.class得到Class實例時,並不會觸發類的初始化,而 Class.forName方法就會觸發,固然實例化對象確定也是會觸發的,但由於static代碼塊只執行一次,因此不會再有打印,最後的打印,說明一個類的Class實例只有惟一的一個。
擴展:
對於Class.forName("")方法,能夠看看下面這篇文章,結合起來理解,會更清晰:理解Class.forName()