java 类型信息

运行时类型信息使得你在程序运行时发现和使用类型信息

我们如何使用类型信息呢?主要有两种方式:一是传统的RTTI,它假设在编译时我们知道所有的类型;二是反射机制,它允许我们在运行时发现和使用类的信息。

为什么使用RTTI(Run-Time Type Identification)

这里写图片描述
实际上他是把所有的对象当Object持有–会自动将结果转型为Shape。这是RTTI的最基本的使用形式,因为在java中,所有的类型都是在运行时检查的。这也是RTTI名字的含义,在运行时,识别一个对象的类型。

class对象

类是程序的一部分,每个类都有一个Class对象。所有的类都是在第一次使用时,动态加载到JVM中的。

package type;

/**
 * Created by leon on 2017/2/25.
 */
public class SweetShop {
    public static void main(String[] args) {
        System.out.println("Inside main...");
        new Candy();
        System.out.println("After createing Candy");
        try {
            Class.forName("type.Gum");
        } catch (ClassNotFoundException e) {
            System.out.println("Couldn't find Gum");
        }
        System.out.println("After Class.forName(\"Gum\")");
        new Cookie();
        System.out.println("After creating Cookie");
    }
}

class Candy{
    static {
        System.out.println("Loading Candy");
    }
}

class Gum{
    static {
        System.out.println("loading Gum");
    }
}

class Cookie{
    static{
        System.out.println("Loading Cookie");
    }
}
Inside main...
Loading Candy
After createing Candy
loading Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie

所有的类的使用都是在第一次使用时,动态加载到JVM中的。当程序创建的第一个对类的静态成员的引用时,就会加载这个类。这个证明构造器也是累的静态方法,即使在构造器前没有使用static关键字。因此,用new操作符创建的新对象也会被当做对类的静态成员的引用。
java程序在它开始运行之前并非完全加载,其各个部分是在必需时才加载的。动态加载能力使能的行为,在诸如C++这样的静态加载的语言中很难或者根本不可能复制的。
类加载器首先会验证Class对象是否完整加载,一旦某各类的Class对象呗载入内存,它会被利用创建这个类的所有对象。
上面每一个类都有一个static字句,该字句在类的第一次加载时执行。
Class.forName(“…”) 是取得Class对象的引用的另一种便捷的方法,因为你不用为了获得Class引用而持有该类型的对象。但但是如果你已经拥有了一个感兴趣的对象,那就调用getClass()方法来获取Class引用了,这个方法属于Object对象的一部分,将返回给对象实际类型Class的引用。Class还包括很多其他有用的方法:

package type;

/**
 * Created by leon on 2017/2/25.
 */
interface HashBatteries{}
interface Waterproof{}
interface Shoots{}
class Toy{
    Toy() {}
    Toy(int i){}
}
class FancyToy extends Toy{
    FancyToy() {
        super(1);
    }
}
public class ToyTesy {
    static void printInfo(Class cc){
        System.out.println("Class name:"+cc.getName()
                +" -- is Interface? :"+cc.isInterface());
        System.out.println("Simple name:"+cc.getSimpleName());
        System.out.println("Canonical name:"+cc.getCanonicalName());
    }

    public static void main(String[] args) {
        Class c = null;
        try {
            c = Class.forName("type.FancyToy");
        } catch (ClassNotFoundException e) {
            System.out.println("Can't find FancyToy");
            e.printStackTrace();
        }
        printInfo(c);
        for (Class aClass : c.getInterfaces()) {
            printInfo(aClass);
        }
        Object obj = null;
        Class up = c.getSuperclass();

        try {
            obj = up.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        printInfo(obj.getClass());
    }
}
Class name:type.FancyToy -- is Interface? :false
Simple name:FancyToy
Canonical name:type.FancyToy
Class name:type.Toy -- is Interface? :false
Simple name:Toy
Canonical name:type.Toy

类字面常量

Java提供另一种方法来生成对Class对象的引用,即类字面常量,对上述程序来说就是Fancy.class 。这样做不仅简单而且更安全,因为在编译时就会受到检查(因此不需要try catch),并且它根除了对forName() 方法的调用,所以更高效。类字面常量不仅可以应用于普通的类,也可以应用于接口、数组、以及基本数据类型。
值得注意的是,使用“.class”来创建对Class对象的引用是,不会自动的初始化该Class对象。准备工作包含三个不走

  1. 加载。 类加载器执行,查找字节码,并从这些字节码中创建一个Class对象。
  2. 链接。 在连接阶段将验证类中的字节码,为静态域分配空间,并且如果必须的话,将解析这个类创建的对其他类的引用。
  3. 初始化。如果该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化代码块。
    初始化被延迟到了对静态方法(构造器隐式地是静态的)或者非静态域进行首次引用是才执行:
package thingkingInJava.type;

import java.util.Random;

/**
 * Created by leon on 2017/3/5.
 */
class Initable{
    static final int staticFinal = 47;
    static final int staticFinal2 =ClassInitialization.rand.nextInt(1000);
    static {
        System.out.println("Initializing Initable");
    }
}

class Initable2{
    static int staticNonFinal = 147;
    static {
        System.out.println("Initializing Initable2");
    }
}

class Initable3{
    static int staticNonFinal = 74;
    static{
        System.out.println("Initializing Initable3");
    }
}

public class ClassInitialization {
    public static Random rand = new Random(47);

    public static void main(String[] args) {
        Class initable = Initable.class;
        System.out.println("After creating Initable ref");
        //Does not trigger initalization
        System.out.println(Initable.staticFinal);

        //Does trigger initalization
        System.out.println(Initable.staticFinal2);

        //Does trigger initalization
        System.out.println(Initable2.staticNonFinal);
        try {
            Class initable3 = Class.forName("thingkingInJava.type.Initable3");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println("After creating Initable3 ref");
        System.out.println(Initable3.staticNonFinal);
    }
}
After creating Initable ref
47
Initializing Initable
258
Initializing Initable2
147
Initializing Initable3
After creating Initable3 ref
74

初始化实现了尽可能的“惰性”。从对initable引用的创建可以看出,仅使用.class语法获取的对类的引用不会引发初始化。但是为了产生Class引用,Class.forName()会立即就进行初始化,就像对initable3引用的创建中看到的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值