java类型信息

运行时类型信息使得你能够在程序运行时发现和使用类型信息;
java在运行中识别类型信息主要有两类,一是从传统的RTTI,另一种是反射机制;


1、Class对象

要理解RTTI是在java中的工作原理,必须要知道,类型信息在运行中是如何表示的,这项工作是由Class类来完成的,它包含了与类有关的信息;
类是程序的一部分,每一个类都有一个Class对象,换言之,每当编写并编译一个新类,就会产生一个Class对象(保存在对应的同名.class文件中),为了生成这个类的对象,java虚拟机将使用成为类加载器的子系统;
所有的类都是在其第一次使用时,动态的加载到JVM中,当程序创建的第一个对类的静态成员的引用时,就会加载此类。这证明构造器也是一种静态方法,即使构造器之前并没有使用关键词static。因此,使用new关键字创造的新对象也会被当作对类的静态成员的引用;
因此,java程序在其开始运行之前并非全部加载,其各个部分只有需要的时候才被加载。

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

上面一个例子证明,类仅在其需要的时候加载,static初始化,是在类加载的时候进行的。
实现class对象的引用方法,可以通过Class.forName()方法,根类的.getClass()方法和.Class方法进行使用;
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()方法,是实现虚拟构造器的一种途径,并且由该方法创建的类,必须含有默认无参构造器;

2、类字面常量

java生成引用的另外一个方法,.class方法,即类字面常量;这样做不仅简单,而且安全,因为他在编译的时候已经检查,故无需采用try语句;它不仅可以应用到普通的类,还可以应用到接口、数组以及基本数据类型;对于包装类型,还有一个标准的字段TYPE;
即对于包装类型:
boolean.class等价于Boolean.TYPE
当使用.class来创建Class对象时,不会自动的初始化该Class对象,为了使用类而做的准备实际上包括三个步骤:
1、加载,有类加载器执行,该步骤查找字节码,并从这些字节码中创建一个Class对象;
2、链接:在链接阶段将验证码类中的字节码,为静态域分配存储空间,同时解析该类创建的对其他类的引用;
3、初始化:如果该类有超类的话,先对其超类进行初始化,执行其静态初始化构造器或静态代码块,而初始化延迟到,对静态方法或者常数静态域进行首次引用;

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("执行FatheClss的构造方法"+"  age"+age+"  name"+name+ str);
    }
    static {
        System.out.println("执行FatherClss的静态代码块"+age+str);
        age=38;
        System.out.println("执行FatherClss的静态代码块"+age+str);
    }
    {
        System.out.println("执行"+this.getClass()+"的非静态代码块"+"   age:"+age+"   name:"+name+str);
        age=12;
        System.out.println("执行"+this.getClass()+"的非静态代码块"+"   age:"+age+"   name:"+name+str);
    }
}
public class CLassLoad extends FatheCLss {
    private static double height;
    public CLassLoad(){
        super();
        System.out.println("执行CLassLoad的构造方法"+height);
    }
    static {
        System.out.println("执行CLassLoad 的静态代码块"+height);
        height=12;
        System.out.println("执行CLassLoad 的静态代码块"+height);
    }
    public static void main(String args[]){
        new CLassLoad();
    }
}


执行class com.FatheCLss的非静态代码块   age:0   name:lihuahello world
执行class com.FatheCLss的非静态代码块   age:12   name:lihuahello world
执行FatheClss的构造方法  age12  namelihuahello world
执行FatherClss的静态代码块1hello world
执行FatherClss的静态代码块38hello world
执行CLassLoad 的静态代码块0.0
执行CLassLoad 的静态代码块12.0
执行class com.CLassLoad的非静态代码块   age:38   name:lihuahello world
执行class com.CLassLoad的非静态代码块   age:12   name:lihuahello world
执行FatheClss的构造方法  age12  namelihuahello world
执行CLassLoad的构造方法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("执行FatheClss的构造方法"+"  age"+age+"  name"+name+ STR);
    }
    static {
        System.out.println("执行FatherClss的静态代码块"+age+STR);
        age=38;
        System.out.println("执行FatherClss的静态代码块"+age+STR);
    }
    {
        System.out.println("执行"+this.getClass()+"的非静态代码块"+"   age:"+age+"   name:"+name+STR);
        age=12;
        System.out.println("执行"+this.getClass()+"的非静态代码块"+"   age:"+age+"   name:"+name+STR);
    }
}
public class CLassLoad {

    public static void main(String args[]){
        Class father=FatheCLss.class;

       System.out.println("before fatherClass 实例化");
        System.out.println(FatheCLss.STR);
        System.out.println("fatheclass 的 str");
        System.out.println(FatheCLss.age);

    }
}


可以看出对于static final修饰的值,代表为编译器常量,不需要对其进行初始化即可得到;
而,一个static域而不是final的,那么对其访问时,总是要求在它被读之前进行链接和初始化;

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

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,296评论 18 399
  • 2.3 Java类型信息详解 运行时类型信息(RTTI)使得我们可以在程序运行时发现和使用类型信息,其工作原理是C...
    jianhuih阅读 1,827评论 0 1
  • 欢迎转载,但请保留作者链接:http://www.jianshu.com/p/5a6bad3752d9 有Java...
    郭非文阅读 4,151评论 4 10
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 昨天参加完学校的迎新晚会,一个人随着人流走回宿舍,并行的同学有夸奖的也有说无聊的,而我认为ta们非常棒。...
    songgenkui阅读 273评论 0 1