Java Class對象詳解(jie)
要怎(zen)樣在java里(li)來(lai)(lai)使用(yong)(yong)一個(ge)類(lei),首先(xian)必須先(xian)把類(lei)的(de).class字節碼文件加載進(jin)來(lai)(lai),然后再(zai)(zai)進(jin)行連(lian)接對該類(lei)里(li)的(de)域分(fen)配內存,最后再(zai)(zai)調用(yong)(yong)構造(zao)器,如果該類(lei)有(you)基類(lei)的(de)話,會先(xian)去(qu)調用(yong)(yong)基類(lei)的(de)構造(zao)器,總的(de)來(lai)(lai)說(shuo),分(fen)為以下三(san)個(ge)步驟。
1.根據環境變量找到并加載.class文件
2.為該類的非編譯時常量分配內存
3.調用該類的構造器
java里的所有類都有一個Class對象,通過這個Class對象我們能夠獲取此類的各種信息。
當某個字節碼文件被JVM加載的時候,Class對象就被創建。
Class類沒有構造方法,是內部的(de)一個defineClass方法來創建(jian)此(ci)對(dui)象的(de),此(ci)對(dui)象與被加載的(de)字(zi)節碼(ma)文件(jian)的(de)類的(de)類型相(xiang)對(dui)應。
其實(shi)在java里包括(kuo)基本數據(ju)類型(int short long byte float double boolean char),也(ye)包括(kuo)了void
System.out.println(int.class.getName());
System.out.println(char.class.getName());
System.out.println(short.class.getName());
System.out.println(long.class.getName());
System.out.println(byte.class.getName());
System.out.println(float.class.getName());
System.out.println(double.class.getName());
System.out.println(boolean.class.getName());
System.out.println(void.class.getName());
都有(you)與之對(dui)應的class對(dui)象(xiang)(xiang),同(tong)類(lei)型(xing)的類(lei)型(xing)也共享(xiang)一個class對(dui)象(xiang)(xiang)。也包括了數(shu)組,所有(you)同(tong)類(lei)型(xing)同(tong)維度的數(shu)組也共享(xiang)一個class對(dui)象(xiang)(xiang)。
public class Main {
public static void main(String[] args) {
System.out.println(char[].class.getName());//[C
System.out.println(char[][].class.getName());//[[C
}
}
class的forName方法
同時class里有一個(ge)static的方法(fa)forName,可以讓我(wo)們顯示的來把(ba)一個(ge)類的.class文件加載至JVM虛(xu)擬機(ji)。
static Class< ? > forName(String className)
public class Main {
public static void main(String[] args) throws Exception{
Class a = Class.forName("A");
}
}
class A{
void print(){
System.out.println("hello world");
}
}
該方法返回的是一個Class對象,這個Class對象也可以添加泛型。
這樣的話我們就獲得一個與A類型對應的Class對象。
但是這(zhe)時編譯器會強(qiang)制的讓我們(men)拋出或者捕獲(huo)這(zhe)個異常,所(suo)以我們(men)需要將它捕獲(huo)或者拋出。
接下來我們(men)還能重載(zai)一個A類的(de)private的(de)構造(zao)器(注:默認(ren)的(de)構造(zao)器是隱式的(de)static,我們(men)重載(zai)之后就(jiu)不(bu)再(zai)是static),但(dan)是我們(men)仍然能獲(huo)取它的(de)class對象(xiang),因為調(diao)用構造(zao)器是在(zai)最(zui)后一步,而我們(men)這里只(zhi)是加(jia)載(zai).class文件。
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class a = Class.forName("A");
}
}
class A{
private A(){
}
void print(){
System.out.println("hello world");
}
}
這(zhe)段(duan)代碼是(shi)毫無錯誤的
但是直(zhi)到現在我(wo)(wo)們都還(huan)不(bu)能通過(guo)Class.forName來操作一個(ge)類(lei),因(yin)為(wei)它只是簡單的(de)加載而(er)已,但是沒關系Class類(lei)還(huan)有一個(ge)newInstance方法,這個(ge)方法能幫助我(wo)(wo)們創建一個(ge)class類(lei)的(de)實(shi)例,我(wo)(wo)們只需顯示的(de)轉換一下(xia)類(lei)型即可操作A類(lei).
public class Main {
public static void main(String[] args) throws Exception {
A a = (A)Class.forName("A").newInstance();
a.print();
}
}
class A{
void print(){
System.out.println("hello world");
}
}
這時(shi),其(qi)實我們得到的(de)就是一個A類型(xing)的(de)實例了。
但是如果我們這時把(ba)A的構(gou)造方法聲(sheng)明為private呢(ni)?
public class Main {
public static void main(String[] args) throws Exception {
A a = (A)Class.forName("A").newInstance();
a.print();
}
}
class A{
private A(){
}
void print(){
System.out.println("hello world");
}
}
編譯(yi)器是(shi)仍(reng)然不會報錯的(de)(de),但是(shi)如果我們執行這段代碼就會發現會拋出一個(ge)異常,因為這是(shi)在(zai)運行時加載的(de)(de),所以(yi)編譯(yi)器是(shi)無法察覺的(de)(de)。這也是(shi)相當危(wei)險的(de)(de),所以(yi)一般(ban)情況下我們都會遵守用(yong)new來創(chuang)建對(dui)象。
既然class是(shi)運行時對象,那么對于(yu)final static 聲(sheng)明的域也是(shi)毫無作用的了,這么說的原因(yin)是(shi)用final static聲(sheng)明的域是(shi)不需要動態的來分配內存(cun)的,因(yin)為它是(shi)一個編(bian)譯時常(chang)量。
到現在我們大概明白了class的含義和運用,那它和.class有什么聯系呢。
其實每個類也(ye)有一(yi)個.class的常(chang)量(liang)(liang),我們(men)稱為類字(zi)面(mian)常(chang)量(liang)(liang),這個常(chang)量(liang)(liang)能(neng)夠返回(hui)該類的class對(dui)象,也(ye)能(neng)通過newIstance創建(jian)實例來操作。
運用(yong)類字面常(chang)量的(de)(de)好處就(jiu)(jiu)在(zai)于不用(yong)去(qu)拋出或者(zhe)捕獲異常(chang),所犯的(de)(de)錯誤在(zai)編(bian)譯時(shi)就(jiu)(jiu)能查找出來。
public class Main {
public static void main(String[] args) throws Exception {
A a = (A)A.class.newInstance();
a.print();
}
}
class A{
void print(){
System.out.println("hello world");
}
}
封裝類的TYPE
這里以boolean類型(xing)來說(shuo)明(ming)這個問題
System.out.println(boolean.class == Boolean.TYPE);//true
所以(yi)我們得出(chu)基本(ben)類(lei)型的(de).class 和(he) 封(feng)裝類(lei)的(de)TYPE是等(deng)價的(de)。
