運(yùn)行時(shí)類型信息使得你能夠在程序運(yùn)行時(shí)發(fā)現(xiàn)和使用類型信息;
java在運(yùn)行中識(shí)別類型信息主要有兩類,一是從傳統(tǒng)的RTTI
,另一種是反射機(jī)制;
1、Class對(duì)象
要理解RTTI
是在java中的工作原理,必須要知道,類型信息在運(yùn)行中是如何表示的,這項(xiàng)工作是由Class類來完成的,它包含了與類有關(guān)的信息;
類是程序的一部分,每一個(gè)類都有一個(gè)Class對(duì)象,換言之,每當(dāng)編寫并編譯一個(gè)新類,就會(huì)產(chǎn)生一個(gè)Class對(duì)象(保存在對(duì)應(yīng)的同名.class文件中),為了生成這個(gè)類的對(duì)象,java虛擬機(jī)將使用成為類加載器的子系統(tǒng);
所有的類都是在其第一次使用時(shí),動(dòng)態(tài)的加載到JVM中,當(dāng)程序創(chuàng)建的第一個(gè)對(duì)類的靜態(tài)成員的引用時(shí),就會(huì)加載此類。這證明構(gòu)造器也是一種靜態(tài)方法,即使構(gòu)造器之前并沒有使用關(guān)鍵詞static
。因此,使用new關(guān)鍵字創(chuàng)造的新對(duì)象也會(huì)被當(dāng)作對(duì)類的靜態(tài)成員的引用;
因此,java程序在其開始運(yùn)行之前并非全部加載,其各個(gè)部分只有需要的時(shí)候才被加載。
package com.innerclass;
class Candy{
static {
System.out.println("Candy has been load...");
}
}
class Gum{
static {
System.out.println("Gum has been load...");
}
}
class Cookie{
static {
System.out.println("Cookie has been load...");
}
}
public class classform {
public static void main(String[] args){
System.out.println("inside main");
new Candy();
System.out.println("After creating Candy");
try{
Class.forName("com.innerclass.Gum");
} catch (ClassNotFoundException e) {
//e.printStackTrace();
System.out.println("Gum not found");
}
/*
try {
Class<?> g=Gum.class;
}catch (Exception e){
System.out.println("未加載成功...");
}
*/
System.out.println("After Class.forName(\"Gum\") ");
new Cookie();
System.out.println("After creating Cookie");
}
}
inside main
Candy has been load...
After creating Candy
Gum has been load...
After Class.forName("Gum")
Cookie has been load...
After creating Cookie
上面一個(gè)例子證明,類僅在其需要的時(shí)候加載,static初始化,是在類加載的時(shí)候進(jìn)行的。
實(shí)現(xiàn)class對(duì)象的引用方法,可以通過Class.forName()
方法,根類的.getClass()
方法和.Class
方法進(jìn)行使用;
Class類還有一些別的方法:
package com.innerclass;
interface Web{}
interface Applaction{}
interface Net{}
class Candy{
static {
System.out.println("Candy has been load...");
}
}
class Gum extends Candy implements Web,Applaction,Net{
static {
System.out.println("Gum has been load...");
}
}
public class classform {
public static void main(String[] args){
Class c=null;
try{
c=Class.forName("com.innerclass.Gum");
} catch (ClassNotFoundException e) {
System.out.println("cannt find Gum");
System.exit(1);
}
System.out.println(c);
for(Class face:c.getInterfaces()){
System.out.println("c.getInterfaces"+face);
Class up=c.getSuperclass();
Object object=null;
try {
object=up.newInstance();
} catch (IllegalAccessException e) {
System.out.println("cannt access");
System.exit(1);
} catch (InstantiationException e) {
System.out.println("cannt instantiate");
System.exit(1);
}
System.out.println("c.getSuperclass"+object.getClass());
}
}
}
注意上例的newInstance()
方法,是實(shí)現(xiàn)虛擬構(gòu)造器的一種途徑,并且由該方法創(chuàng)建的類,必須含有默認(rèn)無參構(gòu)造器;
2、類字面常量
java生成引用的另外一個(gè)方法,.class
方法,即類字面常量;這樣做不僅簡(jiǎn)單,而且安全,因?yàn)樗诰幾g的時(shí)候已經(jīng)檢查,故無需采用try語句;它不僅可以應(yīng)用到普通的類,還可以應(yīng)用到接口、數(shù)組以及基本數(shù)據(jù)類型;對(duì)于包裝類型,還有一個(gè)標(biāo)準(zhǔn)的字段TYPE;
即對(duì)于包裝類型:
boolean.class
等價(jià)于Boolean.TYPE
當(dāng)使用.class
來創(chuàng)建Class對(duì)象時(shí),不會(huì)自動(dòng)的初始化該Class對(duì)象,為了使用類而做的準(zhǔn)備實(shí)際上包括三個(gè)步驟:
1、加載,有類加載器執(zhí)行,該步驟查找字節(jié)碼,并從這些字節(jié)碼中創(chuàng)建一個(gè)Class對(duì)象;
2、鏈接:在鏈接階段將驗(yàn)證碼類中的字節(jié)碼,為靜態(tài)域分配存儲(chǔ)空間,同時(shí)解析該類創(chuàng)建的對(duì)其他類的引用;
3、初始化:如果該類有超類的話,先對(duì)其超類進(jìn)行初始化,執(zhí)行其靜態(tài)初始化構(gòu)造器或靜態(tài)代碼塊,而初始化延遲到,對(duì)靜態(tài)方法或者常數(shù)靜態(tài)域進(jìn)行首次引用;
package com;
class FatheCLss{
private static FatheCLss fatheCLss=new FatheCLss();
private final static String str="hello world";
private static int age=1;
private String name="lihua";
public FatheCLss(){
System.out.println("執(zhí)行FatheClss的構(gòu)造方法"+" age"+age+" name"+name+ str);
}
static {
System.out.println("執(zhí)行FatherClss的靜態(tài)代碼塊"+age+str);
age=38;
System.out.println("執(zhí)行FatherClss的靜態(tài)代碼塊"+age+str);
}
{
System.out.println("執(zhí)行"+this.getClass()+"的非靜態(tài)代碼塊"+" age:"+age+" name:"+name+str);
age=12;
System.out.println("執(zhí)行"+this.getClass()+"的非靜態(tài)代碼塊"+" age:"+age+" name:"+name+str);
}
}
public class CLassLoad extends FatheCLss {
private static double height;
public CLassLoad(){
super();
System.out.println("執(zhí)行CLassLoad的構(gòu)造方法"+height);
}
static {
System.out.println("執(zhí)行CLassLoad 的靜態(tài)代碼塊"+height);
height=12;
System.out.println("執(zhí)行CLassLoad 的靜態(tài)代碼塊"+height);
}
public static void main(String args[]){
new CLassLoad();
}
}
執(zhí)行class com.FatheCLss的非靜態(tài)代碼塊 age:0 name:lihuahello world
執(zhí)行class com.FatheCLss的非靜態(tài)代碼塊 age:12 name:lihuahello world
執(zhí)行FatheClss的構(gòu)造方法 age12 namelihuahello world
執(zhí)行FatherClss的靜態(tài)代碼塊1hello world
執(zhí)行FatherClss的靜態(tài)代碼塊38hello world
執(zhí)行CLassLoad 的靜態(tài)代碼塊0.0
執(zhí)行CLassLoad 的靜態(tài)代碼塊12.0
執(zhí)行class com.CLassLoad的非靜態(tài)代碼塊 age:38 name:lihuahello world
執(zhí)行class com.CLassLoad的非靜態(tài)代碼塊 age:12 name:lihuahello world
執(zhí)行FatheClss的構(gòu)造方法 age12 namelihuahello world
執(zhí)行CLassLoad的構(gòu)造方法12.0
package com;
class FatheCLss{
// private static FatheCLss fatheCLss=new FatheCLss();
static final String STR="hello world";
static int age=1;
int width=12;
final int height=1;
String name="lihua";
public FatheCLss(){
System.out.println("執(zhí)行FatheClss的構(gòu)造方法"+" age"+age+" name"+name+ STR);
}
static {
System.out.println("執(zhí)行FatherClss的靜態(tài)代碼塊"+age+STR);
age=38;
System.out.println("執(zhí)行FatherClss的靜態(tài)代碼塊"+age+STR);
}
{
System.out.println("執(zhí)行"+this.getClass()+"的非靜態(tài)代碼塊"+" age:"+age+" name:"+name+STR);
age=12;
System.out.println("執(zhí)行"+this.getClass()+"的非靜態(tài)代碼塊"+" age:"+age+" name:"+name+STR);
}
}
public class CLassLoad {
public static void main(String args[]){
Class father=FatheCLss.class;
System.out.println("before fatherClass 實(shí)例化");
System.out.println(FatheCLss.STR);
System.out.println("fatheclass 的 str");
System.out.println(FatheCLss.age);
}
}
可以看出對(duì)于static final
修飾的值,代表為編譯器常量,不需要對(duì)其進(jìn)行初始化即可得到;
而,一個(gè)static
域而不是final
的,那么對(duì)其訪問時(shí),總是要求在它被讀之前進(jìn)行鏈接和初始化;