类型信息

Java在运行时识别对象和类的信息有两种方式:
(1)传统的RTTI,假定在编译时已经知道了所有类型;
(2)反射机制,允许在运行时发现和使用类的信息。
1.为什么需要RTTI
在Java中,所有的类型转换都是在运行时进行正确性检查。
2.Class对象
Java使用Class对象来执行其RTTI;每当编写并编译了一个新类,就会产生一个Class对象(被保存在一个同名的.class文件中)
所有的类都是在对其第一次使用时,动态加载到JVM中的。程序创建第一个对类的静态成员的引用时,就会加载这个类。构造器也是类的静态方法,new操作符创建类的新对象也会被当做对类的静态成员的引用。
Java程序在开始运行之前并非被完全加载,各个部分是在必须时才加载的。(C++为静态加载语言

    Class.forName("类名");
    //此方法为Class类的一个static成员。是取得Class对象的引用的一种方法。
    //如果找不到要加载的类,会抛出ClassNotFoundException异常。
    //只要想在运行时使用类型信息,就必须首先获得对恰当Class对象的引用。Class.forName()就是便捷途径
    //区分getClass():他将返回表示该对象的实际类型的Class引用。
    Class类包含的常用方法(设有类com.dao.Test(Test.class)):
    c.getName():com.dao.Test
    c.isInterface():false
    c.getSimpleName():Test
    c.getCanonicalName():com.dao.Test
    c.getInterfaces():返回对象中包含的接口
    c.getSuperclass():返回直接基类
    c.newInstance():实现“虚拟构造器”的一种途径,创建的类必须带有默认构造器
2.1类字面常量
     Test.class;//生成对Class对象的引用,在编译时就会受到检查(不需至于try中)根除对forName()的调用,
     更高效不仅可以应用于普通类,也可应用于接口、数组及基本数据类型。  
     仅使用.class语法获得对类的引用不会引发初始化。但为了产生Class引用,Class.forName()立即就进行了初
     始化。
   如果一个static final值是“编译期常量”,那么这个值不需要对类进行初始化就可被读取。如果一个static域不是final的,那么在对他访问时,要先进行链接(为域分配存储空间)和初始化(初始化存储空间)。
        import java.util.*;
        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) throws Exception {
        Class initable = Initable.class;
        System.out.println("After creating Initable ref");
        // Does not trigger initialization:
        System.out.println(Initable.staticFinal);
        // Does trigger initialization:
        System.out.println(Initable.staticFinal2);
        // Does trigger initialization:
        System.out.println(Initable2.staticNonFinal);
        Class initable3 = Class.forName("Initable3");
        System.out.println("After creating Initable3 ref");
        System.out.println(Initable3.staticNonFinal);
        }
      } /* Output:
      After creating Initable ref
      47
      Initializing Initable
      258
      Initializing Initable2
      147
      Initializing Initable3
      After creating Initable3 ref
      74
      *///:~
 2.2泛化的Class引用
     Class引用表示的就是它所指向的对象的确切类型,而该对象便是Class类的一个对象。
     通过使用泛型语法,可以让编译器强制执行额外的类型检查。    
         Class<? extends Number> test = int.class;
         test = double.class;
         // ? :通配符
         //向Class引用添加泛型语法的原因仅仅是为了提供编译器类型检查,此时newInstance()将返回该对象的确切类
         //型。一个例外:超类 Class<? super xxx>
 2.3新的转型语法
     cast()方法;

3.类型转换前先做检查
编译期,若不使用显示的类型转换,编译器不允许执行向下转型赋值。进行向下转型前,若无其他信息告知对象类型,则使用instanceof是非常必要的,否则会得到一个ClassCastException异常。

 if(x instanceof Dog)
   ((Dog)x).bark();

3.1使用类字面常量

6.反射:运行时的类信息
RTTI可以获得某个对象的确切类型,但有个限制:这个类型在编译时必须已知。
反射提供了一种机制——用来检查可用的方法,并返回方法名。Java通过JavaBeans提供了基于构件的编程架构
Class类与java.lang.reflect类库一起对反射进行了支持,该类库包含了Field、Method及Constructor类(每个
类都实现了Member接口)。这些类型的对象是由JVM在运行时创建的,用以表示未知类里的成员
(1)使用Constructor创建新对象
(2)用get()和set()方法读取和修改与Field对象关联的字段
(3)用invoke()方法调用与Method对象关联的方法。
(4)可以调用getFields()、getMethods()、getConstructors()等方法,返回表示字段、方法及构造器的对象的数
组。
未知类型对象所属的类的.class文件对于JVM来说必须是可获得的。
RTTI与反射区别:
RTTI,编译器在编译时打开和检查.class文件;
反射,在运行时打开和检查.class文件(编译时不可获取)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值