Thinking in Java 第14章 类型信息


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


本文发表于KuTear's Blog,转载请注明

Class

构造器/Static块初始化顺序

单一类的情况(没有继承)

对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是(静态变量、静态初始化块)>(变量、初始化块)>构造器。

public class InitialOrderTest {
        /* 静态变量 */
    public static String staticField = "静态变量";
        /* 变量 */
    public String field = "变量";
        /* 静态初始化块 */
    static {
        System.out.println( staticField );
        System.out.println( "静态初始化块" );
    }
        /* 初始化块 */
    {
        System.out.println( field );
        System.out.println( "初始化块" );
    }
        /* 构造器 */
    public InitialOrderTest(){
        System.out.println( "构造器" );
    }


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

输出

静态变量
静态初始化块
变量
初始化块
构造器

包含继承关系的时候

static class Parent {
        /* 静态变量 */
        public static String p_StaticField = "父类--静态变量";
        /* 变量 */
        public String    p_Field = "父类--变量";
        protected int    i    = 9;
        protected int    j    = 0;
        /* 静态初始化块 */
        static {
            System.out.println( p_StaticField );
            System.out.println( "父类--静态初始化块" );
        }
        /* 初始化块 */
        {
            System.out.println( p_Field );
            System.out.println( "父类--初始化块" );
        }
        /* 构造器 */
        public Parent(){
            System.out.println( "父类--构造器" );
            System.out.println( "i=" + i + ", j=" + j );
            j = 20;
        }
    }

    public static class SubClass extends Parent {
        /* 静态变量 */
        public static String s_StaticField = "子类--静态变量";
        /* 变量 */
        public String s_Field = "子类--变量";
        /* 静态初始化块 */
        static {
            System.out.println( s_StaticField );
            System.out.println( "子类--静态初始化块" );
        }
        /* 初始化块 */
        {
            System.out.println( s_Field );
            System.out.println( "子类--初始化块" );
        }
        /* 构造器 */
        public SubClass(){
            System.out.println( "子类--构造器" );
            System.out.println( "i=" + i + ",j=" + j );
        }
    }

现在实例化一个SubClass将得到以下的输出

父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
父类--变量
父类--初始化块
父类--构造器
i=9, j=0
子类--变量
子类--初始化块
子类--构造器
i=9,j=20

由此我们知道父类构造器先于子类构造器调用,当在父类构造器中添加钩子函数时要注意,有可能子类实现的钩子函数中用到的参数没有被初始化。

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();  //当调用时 mVar==null
  }
}

常用方法

常用方法 方法说明
isInterface() 判断是否在接口
getInterfaces() 获取class实现的所有接口
getSuperclass() 获取class的直接父类
newInstance() 实例化对象,必须含有默认构造器
getPrimitiveClass(String) 获取原始类型对应的Class(Integer.TYPE等的实现)
cast(Object) 转化Object为具体的类型(Class< T > 中的T)
isAssignableFrom(Class<?>) 判断传入的class是否为当前class的子类或就是当前类
getModifiers() 返回当前class的修饰符(public/private/protect等等)
getMethod(String, Class<?>...) 根据方法名字参数类型获取方法

类字面常量

使用类必须要准备三个步骤:

  1. 加载,这是由类加载器执行的。该步骤还将查找字节码,并从这些字节码中创建一个Class对象;
  2. 链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类的创建的对其他类的所有引用。
  3. 初始化,如果该类有超类,则对其初始化,执行静态初始化器和静态初始化块。

字面常量就是ClassName.class的形式。在Android启动Activity的时候经常都有使用。

类加载

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

上面的代码中,clazz1不会加载OneClassJVM,然而clazz2回加载。
初始化被延迟到了对静态方法(构造器也是隐式静态方法)或非常数静态域进行首次引用才执行。

clas Initable{
 public final static int staticFinal = 1; //常数静态域,不会加载class
 public final static double staticFinal2 = Math.random();
 public static double staticVar = 1; 
}

动态代理

    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

通过使用代理,我们可以在函数调用前执行一些操作。

QA

判断一个Class是否为抽象类/接口?

判断接口

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

判断抽象类

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

一个class被加载到JVM后会不会再重JVM中移除?

这个问题是看书过程中想到的,查阅资料才发现需要深入了解JVM,这里只是初步说明。
关于java虚拟机规范中时如何阐述类型卸载(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语言规范提供的关于类型卸载的更详细的信息(部分摘录):

  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

通过以上我们可以得出结论: 类型卸载(unloading)仅仅是作为一种减少内存使用的性能优化措施存在的,具体和虚拟机实现有关,对开发者来说是透明的

instaceof原理

instaceof表示“你是这个类吗,或者是它的子类吗”
==则仅仅表示“你是这个类吗”
深入了解请看RednaxelaFX的知乎回答

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,296评论 18 399
  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 2,584评论 0 11
  • 1、.java源文件: 一个以”.java“为后缀的源文件:只能有一个与文件名相同的类,可以包含其他类。 2、类方...
    Hughman阅读 1,406评论 1 9
  • 昨天到家,看到茶几上老爸放着几本《随笔》在看,封面崭新,就问,你买了随笔看啊?答,不是,你们的书。那书,被我放在书...
    冠世墨玉yanzi阅读 169评论 0 0
  • 处在纸醉金迷的时代,物质成果与心灵要求之间的尖锐矛盾最是忧思。我们过分专一地投身于追求所谓的功名利禄,其结果会使我...
    阿木可阅读 308评论 0 0