本章主要学习如何让我么在运行时识别对象和类的信息的.主要有两种方式:一种是传统的RTTI它假定我们在编译时已经知道了所有的类型. 另一种是反射机制它允许我们在运行时发现和使用类的信息.

1 为什么需要RTTI

  1. RTTI :在运行时识别一个对象的类型

2.反射 允许在运行时发现和使用类型信息

3.传统的RTTI 在编译期通过Class文件识别类型信息,反射在运行期通过Class文件识别类型信息。

4.Java类型转换都发生在运行时期。

2 Class对象

Class对象是用来创建类的所有的"常规"对象的.java使用Class对象来执行其RTTI,即使你正在执行的是转型这样的操作.

Java使用Class对象来执行RTTI。

每个类都有Class对象,即编译了一个新类就会产生一个该类的Class对象,并且保存在.class文件中。Class对象就是用来产生“常规”对象的。

类加载器

所有类都是第一次使用时动态加载到jvm中。

动态加载就是需要时再加载不使用不加载。

只要创建了对一个类的静态成员的引用就会加载该类。new 的时候加载类说明

类的构造器虽然没写static但也是静态方法。因此,使用new操作符创建类的新对象也会被当作对类对静态成员对引用

一旦某个类的Class对象载入内存后,他就会用来创建该类的对象。

运行时要获得一个类的信息(类型信息)可以通过一个该类的Class对象获得,使用Class.forName()就可以做到,而不必持有该类型的对象通过该对象获得。

package typeinfo;

import static net.mindview.util.Print.print;

class Candy {
    static {
        print("Loading Candy");
    }
}

class Gum { // 口香糖
    static {
        print("Loading Gum");
    }
}

class Cookie {
    static {
        print("Loading Cookie");
    }
}

public class SweetShop {
    public static void main(String[] args) {
        print("inside main");
        new Candy();
        print("After creating Candy");
        try {
            Class.forName("typeinfo.Gum"); // 与书有区别  typeinfo.Gum 全限定名  // 返回的是一个Class对象的引用
            Class.forName("Gum"); // 如果获取失败会抛出异常 ClassNotFoundException
        } catch (ClassNotFoundException e) {
            print("Couldn't find Gum");
        }
        print("After Class.forName(\"Gum\")");
        new Cookie();
        print("After creating Cookie");
    }
}
/* 
inside main
Loading Candy
After creating Candy
Couldn't find Gum
After Class.forName("Gum")
Loading Cookie
After creating Cookie
 */

如果有了一个实例对象可以调用getClass()方法来获得Class对象, 这个方法属于根类Object的一部分

Class包含很多有用的方法,下面是其中的一部分

getName() 获得全限定类名, getCanonicalName()也是获得全限定类名。对于普通类来说,二者没什么区别,只是对于特殊的类型上有点表示差异。
getSimpleName()只获得类名,没有包名。
isInterface()判断是否为接口。
getInterfaces() 返回一个Class对象数组,数组元素是该类实现的接口,元素顺序和实现顺序一致。
getSuperclass() 返回直接基类(不是接口)的Class对象,可以用来发现对象完整的类继续结构。
newInstance()创建该类实例对象并返回,但该类必须要有默认构造器,这个方法相当于一个虚拟构造器。

package typeinfo.toys;

import static net.mindview.util.Print.print;

interface HasBatteries{}
interface Waterproof{}
interface Shoots{}

class Toy{
    // Comment out the following default constructor
    // to see NoSuchMethodError from (*1*)
//    Toy(){}
    Toy(int i){}
}

class FancyToy extends Toy implements HasBatteries,Waterproof,Shoots{
    FancyToy(){
        super(1);
    }
}

public class ToyTest {
    static void printInfo(Class cc){
        print("Class name: " + cc.getName() +
                " is interface ? [" + cc.isInterface() +"]");
        print("Simple name: " + cc.getSimpleName());
        print("Canonical name: " + cc.getCanonicalName());
    }

    public static void main(String[] args) {
        Class c = null;
        try{
            c = Class.forName("typeinfo.toys.FancyToy");
        }catch (ClassNotFoundException e){
            print("Can't find FancyToy");
            System.exit(1);
        }

        printInfo(c);

        for (Class face:c.getInterfaces())
            printInfo(face);

        Class up = c.getSuperclass();
        Object obj = null;
        try{
            // Requires default constructor:
            obj = up.newInstance();
        }catch (InstantiationException e){
            print("Cannot instantiate");
            System.exit(1);
        }catch (IllegalAccessException e){
            print("Cannot access");
            System.exit(1);
        }
        printInfo(obj.getClass());
    }
}
/*
Class name: typeinfo.toys.FancyToy is interface ? [false]
Simple name: FancyToy
Canonical name: typeinfo.toys.FancyToy
Class name: typeinfo.toys.HasBatteries is interface ? [true]
Simple name: HasBatteries
Canonical name: typeinfo.toys.HasBatteries
Class name: typeinfo.toys.Waterproof is interface ? [true]
Simple name: Waterproof
Canonical name: typeinfo.toys.Waterproof
Class name: typeinfo.toys.Shoots is interface ? [true]
Simple name: Shoots
Canonical name: typeinfo.toys.Shoots
Cannot instantiate
 */


 posted on 2019-11-22 10:42  erinchen  阅读(100)  评论(0编辑  收藏  举报