Thinking in Java 第14章 類型信息


date: 2016-09-03 12:07
status: public
tags:[Thinking In Java]
title: 'Thinking in Java 第14章 類型信息'


本文發(fā)表于KuTear's Blog,轉(zhuǎn)載請(qǐng)注明

Class

構(gòu)造器/Static塊初始化順序

單一類的情況(沒(méi)有繼承)

對(duì)于靜態(tài)變量、靜態(tài)初始化塊、變量、初始化塊、構(gòu)造器,它們的初始化順序依次是(靜態(tài)變量、靜態(tài)初始化塊)>(變量、初始化塊)>構(gòu)造器。

public class InitialOrderTest {
        /* 靜態(tài)變量 */
    public static String staticField = "靜態(tài)變量";
        /* 變量 */
    public String field = "變量";
        /* 靜態(tài)初始化塊 */
    static {
        System.out.println( staticField );
        System.out.println( "靜態(tài)初始化塊" );
    }
        /* 初始化塊 */
    {
        System.out.println( field );
        System.out.println( "初始化塊" );
    }
        /* 構(gòu)造器 */
    public InitialOrderTest(){
        System.out.println( "構(gòu)造器" );
    }


    public static void main( String[] args ){
        new InitialOrderTest();
    }
}

輸出

靜態(tài)變量
靜態(tài)初始化塊
變量
初始化塊
構(gòu)造器

包含繼承關(guān)系的時(shí)候

static class Parent {
        /* 靜態(tài)變量 */
        public static String p_StaticField = "父類--靜態(tài)變量";
        /* 變量 */
        public String    p_Field = "父類--變量";
        protected int    i    = 9;
        protected int    j    = 0;
        /* 靜態(tài)初始化塊 */
        static {
            System.out.println( p_StaticField );
            System.out.println( "父類--靜態(tài)初始化塊" );
        }
        /* 初始化塊 */
        {
            System.out.println( p_Field );
            System.out.println( "父類--初始化塊" );
        }
        /* 構(gòu)造器 */
        public Parent(){
            System.out.println( "父類--構(gòu)造器" );
            System.out.println( "i=" + i + ", j=" + j );
            j = 20;
        }
    }

    public static class SubClass extends Parent {
        /* 靜態(tài)變量 */
        public static String s_StaticField = "子類--靜態(tài)變量";
        /* 變量 */
        public String s_Field = "子類--變量";
        /* 靜態(tài)初始化塊 */
        static {
            System.out.println( s_StaticField );
            System.out.println( "子類--靜態(tài)初始化塊" );
        }
        /* 初始化塊 */
        {
            System.out.println( s_Field );
            System.out.println( "子類--初始化塊" );
        }
        /* 構(gòu)造器 */
        public SubClass(){
            System.out.println( "子類--構(gòu)造器" );
            System.out.println( "i=" + i + ",j=" + j );
        }
    }

現(xiàn)在實(shí)例化一個(gè)SubClass將得到以下的輸出

父類--靜態(tài)變量
父類--靜態(tài)初始化塊
子類--靜態(tài)變量
子類--靜態(tài)初始化塊
父類--變量
父類--初始化塊
父類--構(gòu)造器
i=9, j=0
子類--變量
子類--初始化塊
子類--構(gòu)造器
i=9,j=20

由此我們知道父類構(gòu)造器先于子類構(gòu)造器調(diào)用,當(dāng)在父類構(gòu)造器中添加鉤子函數(shù)時(shí)要注意,有可能子類實(shí)現(xiàn)的鉤子函數(shù)中用到的參數(shù)沒(méi)有被初始化。

abstract class Parent{
  public Parent(){
    hook();
  }
  public abstract void hook();
}

class Sub extends Parent{
  private SomeVar mVar;
  public Sub(){
     mVar = new SomeVar(); 
  }
  public void hook(){
    mVar.doSomeThing();  //當(dāng)調(diào)用時(shí) mVar==null
  }
}

常用方法

常用方法 方法說(shuō)明
isInterface() 判斷是否在接口
getInterfaces() 獲取class實(shí)現(xiàn)的所有接口
getSuperclass() 獲取class的直接父類
newInstance() 實(shí)例化對(duì)象,必須含有默認(rèn)構(gòu)造器
getPrimitiveClass(String) 獲取原始類型對(duì)應(yīng)的Class(Integer.TYPE等的實(shí)現(xiàn))
cast(Object) 轉(zhuǎn)化Object為具體的類型(Class< T > 中的T)
isAssignableFrom(Class<?>) 判斷傳入的class是否為當(dāng)前class的子類或就是當(dāng)前類
getModifiers() 返回當(dāng)前class的修飾符(public/private/protect等等)
getMethod(String, Class<?>...) 根據(jù)方法名字參數(shù)類型獲取方法

類字面常量

使用類必須要準(zhǔn)備三個(gè)步驟:

  1. 加載,這是由類加載器執(zhí)行的。該步驟還將查找字節(jié)碼,并從這些字節(jié)碼中創(chuàng)建一個(gè)Class對(duì)象;
  2. 鏈接。在鏈接階段將驗(yàn)證類中的字節(jié)碼,為靜態(tài)域分配存儲(chǔ)空間,并且如果必須的話,將解析這個(gè)類的創(chuàng)建的對(duì)其他類的所有引用。
  3. 初始化,如果該類有超類,則對(duì)其初始化,執(zhí)行靜態(tài)初始化器和靜態(tài)初始化塊。

字面常量就是ClassName.class的形式。在Android啟動(dòng)Activity的時(shí)候經(jīng)常都有使用。

類加載

Class clazz1 = OneClass.class
Class clazz2 = Class.forName("OnClass");

上面的代碼中,clazz1不會(huì)加載OneClassJVM,然而clazz2回加載。
初始化被延遲到了對(duì)靜態(tài)方法(構(gòu)造器也是隱式靜態(tài)方法)或非常數(shù)靜態(tài)域進(jìn)行首次引用才執(zhí)行。

clas Initable{
 public final static int staticFinal = 1; //常數(shù)靜態(tài)域,不會(huì)加載class
 public final static double staticFinal2 = Math.random();
 public static double staticVar = 1; 
}

動(dòng)態(tài)代理

    public static void main(String[] args) {
        A a = new A();
        IA proxyA = (IA) Proxy.newProxyInstance(a.getClass().getClassLoader(),new Class[]{
            IA.class
        },new ProxyA(a));
        proxyA.doSomeThing();
    }

    public static interface IA{
        public void doSomeThing();
    }

    public static class A implements IA{
        @Override
        public void doSomeThing(){
            System.out.println("do some thing");
        }
    }

    public static class ProxyA implements InvocationHandler{

        private Object real;
        public ProxyA(Object real) {
            this.real = real;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("before do some thing");
            return method.invoke(real,args);
        }
    }

輸出

before do some thing
do some thing

通過(guò)使用代理,我們可以在函數(shù)調(diào)用前執(zhí)行一些操作。

QA

判斷一個(gè)Class是否為抽象類/接口?

判斷接口

  Class a = IA.class;
  System.out.println(a.isInterface());

判斷抽象類

  Class a = AbstractA.class;
  int modifier =  a.getModifiers(); //獲取修飾符
  System.out.println(Modifier.isAbstract(modifier));

一個(gè)class被加載到JVM后會(huì)不會(huì)再重JVM中移除?

這個(gè)問(wèn)題是看書(shū)過(guò)程中想到的,查閱資料才發(fā)現(xiàn)需要深入了解JVM,這里只是初步說(shuō)明。
關(guān)于java虛擬機(jī)規(guī)范中時(shí)如何闡述類型卸載(unloading)的:

A class or interface may be unloaded if and only if its class loader is unreachable. The bootstrap class loader is always reachable; as a result, system classes may never be unloaded.

再看一下Java語(yǔ)言規(guī)范提供的關(guān)于類型卸載的更詳細(xì)的信息(部分摘錄):

  1. An implementation of the Java programming language may unload classes.
  2. Class unloading is an optimization that helps reduce memory use. Obviously,the semantics of a program should not depend on whether and how a system chooses to implement an optimization such as class unloading.
  3. Consequently,whether a class or interface has been unloaded or not should be transparent to a program

通過(guò)以上我們可以得出結(jié)論: 類型卸載(unloading)僅僅是作為一種減少內(nèi)存使用的性能優(yōu)化措施存在的,具體和虛擬機(jī)實(shí)現(xiàn)有關(guān),對(duì)開(kāi)發(fā)者來(lái)說(shuō)是透明的

instaceof原理

instaceof表示“你是這個(gè)類嗎,或者是它的子類嗎”
==則僅僅表示“你是這個(gè)類嗎”
深入了解請(qǐng)看RednaxelaFX的知乎回答。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,637評(píng)論 18 399
  • 一:java概述:1,JDK:Java Development Kit,java的開(kāi)發(fā)和運(yùn)行環(huán)境,java的開(kāi)發(fā)工...
    ZaneInTheSun閱讀 2,805評(píng)論 0 11
  • 1、.java源文件: 一個(gè)以”.java“為后綴的源文件:只能有一個(gè)與文件名相同的類,可以包含其他類。 2、類方...
    Hughman閱讀 1,739評(píng)論 1 9
  • 昨天到家,看到茶幾上老爸放著幾本《隨筆》在看,封面嶄新,就問(wèn),你買了隨筆看啊?答,不是,你們的書(shū)。那書(shū),被我放在書(shū)...
    冠世墨玉yanzi閱讀 210評(píng)論 0 0
  • 處在紙醉金迷的時(shí)代,物質(zhì)成果與心靈要求之間的尖銳矛盾最是憂思。我們過(guò)分專一地投身于追求所謂的功名利祿,其結(jié)果會(huì)使我...
    阿木可閱讀 508評(píng)論 0 0

友情鏈接更多精彩內(nèi)容