java 类型信息

来源:互联网 发布:centos搭建smtp服务器 编辑:程序博客网 时间:2024/05/21 15:05

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

我们如何使用类型信息呢?主要有两种方式:一是传统的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 CandyAfter createing Candyloading GumAfter Class.forName("Gum")Loading CookieAfter 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? :falseSimple name:FancyToyCanonical name:type.FancyToyClass name:type.Toy -- is Interface? :falseSimple name:ToyCanonical 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 ref47Initializing Initable258Initializing Initable2147Initializing Initable3After creating Initable3 ref74

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

0 0
原创粉丝点击