• RTTI


    Java中有两种方式让我们在运行时识别对象的类的信息:传统的RTTI(Run-Time Type Identification)和反射。

    Class对象

    Class对象包含了与类有关的信息,用来创建类的所有“常规”对象的特殊对象。每一个类都有一个Class对象。

    创建Class对象的引用

    可以用两种方式来创建Class对象引用:Class.forName()和类字面常量。

    创建一个类Farther:

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

    用Class.forName()来创建引用,forName()的参数必须是包含报名的全限定名,并且在找不到类时会抛出ClassNotFoundException:

    Class c = null;
    try {
        c = Class.forName("typeinfo.toys.Farther");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    System.out.println("已创建引用");
    /*
     * 输出:
     * loading farther
     * 已创建引用
     */

     用类字面常量创建引用:

    Class c = null;
    c = Farther.class;
    /*
     * 输出:
     * 已创建引用
     */

    可以发现在使用类字面常量时没有执行Farther类的静态初始化块,这是因为初始化被延迟到了对静态方法或非常数静态域(被static 和 final修饰的常量域)进行首次引用时才执行。

    class Farther {
        static final int test = 1;
        static final int test2 = (int)(Math.random()*10)+1;
        Farther() {}
        static {System.out.println("loading farther");}
    }
    public class Test {
        public static void main(String[] args) {
            Class c = Farther.class;
            System.out.println(Farther.test);
            System.out.println(Farther.test2);
        }
    }
    /*
     * 输出:
     * 1
     * loading farther
     * 7
     */

    Class类的一些常用方法

    package tests;
    
    interface inte1 {}
    interface inte2 {}
    interface inte3 {}
    
    class Farther {
        static final int test = 1;
        static final int test2 = (int)(Math.random()*10)+1;
        Farther() {}
        static {System.out.println("loading farther");}
    }
    
    class Child extends Farther implements inte1, inte2 {
        Child() {}
        static {System.out.println("loading child");}
    }
    
    public class ThinkInJavaTest {
        static void print(Object obj) {System.out.println(obj);}
        
        public static void main(String[] args) {
            Class child = null;
            try {
                child = Class.forName("tests.Child");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            
            print("Child getName: " + child.getName());
            print("Child getSimpleName: " + child.getSimpleName());
            print("Child getCanonicalName: " + child.getCanonicalName());
            for(Class inte : child.getInterfaces()) 
                print(inte.getSimpleName());
            Class farther = child.getSuperclass();
            Object obj = null;
            try {
                obj = farther.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            print(obj.getClass().getSimpleName());
            
            Child[] a = new Child[10];
            print(a.getClass().getName());
            print(a.getClass().getSimpleName());
            print(a.getClass().getCanonicalName());
        }
    }
    /*
     * 输出:
     * loading farther
     * loading child
     * Child getName: tests.Child
     * Child getSimpleName: Child
     * Child getCanonicalName: tests.Child
     * inte1
     * inte2
     * Farther
     * [Ltests.Child;
     * Child[]
     * tests.Child[]
     */

    getSimpleName()返回不带包名的类名,getName()和getCanonicalName()返回全限定名。最后几行代码演示了getName()和getCanonicalName()用于数组时的不同。

    getInterfaces()以数组形式返回这个类所代表的实体(类,接口,基本数据类型或void)实现的接口的Class对象。

    getSuperclass()返回这个类所代表的实体(类,接口,基本数据类型或void)的超类。

    newInstance()新建一个此类型的实例,这个类必须有无参构造器;如果这个Class代表抽象类、接口、基本类型、数组、void中的其中一个或者没有无参构造器则会抛出InstantiationException。

    Class引用和泛型

     我们可以通过泛型语法来限定Class引用所指向的Class对象的类型的类型。

    Class a = Child.class;
    Class<?> b = Child.class;
    Class<Farther> c = Farther.class;
    Class<? extends Farther> d = Child.class;
    Class<? super Child> e = Farther.class;
    a = Farther.class;
    b = Farther.class;
    d = Farther.class;
    e = Child.class;

    其中Class<?> 与普通的Class等价,但是普通的Class会出现警告。

    Child虽然是Farther的子类但是不能使用 c = Child.class 因为 Child Class不是Farther Class的子类对象。

    下面演示了对不同泛型的Class引用调用newInstance所返回的类型。

    try{
        Object obj = a.newInstance();
        obj = b.newInstance();
        Farther far = c.newInstance();
        far = d.newInstance();
        obj = e.newInstance();
    } catch(Exception ex) {
        print("newInstance 失败");
    }

    类型检查

    instanceof

    关键字instanceof返回一个布尔值,告诉我们是不是某个特定类型的实例。

    Child c = new Child();
    if(c instanceof Child) print("is a child");
    if(c instanceof Farther) print("is a farther");
    /*
    loading farther
    loading child
    child
    farther
    */

    但是instanceof只能使用类型名称,这样的话在一些情况下需要写很多的instanceof。

    动态的instanceof

     也可以使用Class对象的isInstance()方法:

    public class Test {
        static void print(Object obj) {System.out.println(obj);}
        
        static boolean judge(Class c, Object obj) {
            return c.isInstance(obj);
        }
        
        public static void main(String[] args) {
            Class<Farther> fc = Farther.class;
            Child ch = new Child();
            print(judge(fc, ch));
            
        }
    }
    /*
    loading farther
    loading child
    true
    */

    这样就不再需要写很多的instanceof了

    直接比较Class对象

    当然也可以直接比较Class对象:

    public class Test {
        static void print(Object obj) {System.out.println(obj);}
        
        public static void main(String[] args) {
            Class fc = Farther.class;
            Child ch = new Child();
            Farther fa = new Farther();
            print(fc == ch.getClass());
            print(fc == fa.getClass());
            print(fc.equals(ch.getClass()));
            print(fc.equals(fa.getClass()));
        }
    }
    /*
    loading farther
    loading child
    false
    true
    false
    true
    */

    与instanceof的区别在于直接比较没有考虑继承,并且使用了泛型语法时可能不能用 == 来比较。

  • 相关阅读:
    获取Web打印的实际打印次数
    Web打印的在线设计
    上海交易所的STEP/FIX/FAST协议解析
    回忆我的姑妈
    指定Web打印的打印机
    Web打印控件设计
    最终用户在线设计和修改Web报表
    NOIP2021 游记
    gym103427 部分题解
    gym103428 部分题解
  • 原文地址:https://www.cnblogs.com/FJH1994/p/5103971.html
Copyright © 2020-2023  润新知