zoukankan      html  css  js  c++  java
  • Java类型信息

    一、引言

      最近在阅读《Java编程思想》,学习一下java类型信息,现在做一下总结。Java如何让我们在运行时识别对象和类的信息的。主要有两种方式:一种是传统的“RTTI”,它假定我们在编译时已经知道了所有的类型;另一种是“反射”机制,它允许我们在运行时发现和使用类的信息。

    二、Class对象

       要理解RTTI的工作原理,首先必须知道类型信息在运行时是如何表示的。这项工作是由称为Class对象的特殊对象完成的,它包含了与类有关的信息。事实上,Class对象就是用来创建类的所有“常规”对象的。Java使用Class对象来执行RTTI,即使你正在执行的是类似转型这样的操作。Class类还拥有大量使用RTTI的其它方式。

       类是程序的一部分,每个类都有一个Class对象。换言之,每当编写并且编译一个新类,就会产生一个Class对象(更恰当的说,是被保存在一个同名.class文件中)。为了生成这个类的对象,运行这个程序的Java虚拟机(JVM)将使用被称为“类加载器”的子系统。

      类加载器子系统实际上可以包含一条类加载器链,但是只有一个原生类加载器。它是JVM实现的一部分。原生类加载器加载的是所谓的可信类,它包括Java API类,它们通常是从本地盘加载的。在这条链中,通常不需要额外的类加载器,但是如果你有特殊需求(例如以某种特殊方式加载类,以支持Web服务器应用,或者在网络中下载类),那么你有一种方式可以挂接这个额外的类加载器。

       所有的类都是在对其第一次使用时候,动态加载到JVM中的。当程序创建第一个对类的静态成员引用时,就会加载这个类。这个证明构造器也是类的静态方法,即使在构造器之前并没有使用static关键字。因此使用new 操作符创建的新的类对象也会被当做是对类的静态成员的引用。

    三、Class对象的生成方式如下

      1.Class.forName("类名字符串")

      2.类名.class

      3.实例对象.getClass()

    四、为了使用类而做的准备工作实际包含三个步骤:

      1.加载。  这是由类加载器执行的。该步骤将查找字节码(通常在classpath所指的路径中查找,但并非是必需的),并从这些字节码中创建一个Class对象。

      2.链接。 在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建对其他类的所有引用。

      3.初始化。 如果该类具有超类,则对其超类初始化,执行静态初始化器和静态初始化块。初始化被延迟到了对静态方法(构造器隐式的是静态的)或者非常数静态域进行首次引用时才执行:

    下面是一个初始化的例子

     1 import java.util.Random;
     2 
     3 class Initable{
     4     static final int staticFinal = 47 ;
     5     static final int staticFinal2 =
     6             ClassInitialization.random.nextInt(1000);
     7     static {
     8         System.out.println("Initialzing Initable");
     9     }
    10     
    11 }
    12 
    13 class Initable2{
    14     static final int staticNonFinal = 147 ;
    15     static{
    16         System.out.println(" Initializing Initable2 ");
    17     }
    18 }
    19 
    20 class Initable3{
    21     static int staticNoFinal = 74 ;
    22     static {
    23         System.out.println("Initializing Initable3");
    24     }
    25 }
    26 
    27 public class ClassInitialization {
    28     public static Random random = new Random(47);
    29     
    30     public static  void main(String[] args) throws Exception{
    31         Class initable = Initable.class ;
    32         System.out.println("After creating Initable ref");
    33         
    34         System.out.println(Initable.staticFinal);
    35         
    36         System.out.println(Initable.staticFinal2);
    37         
    38         System.out.println(Initable2.staticNonFinal);
    39         
    40         Class initable3 = Class.forName("Initable3") ;
    41         
    42         System.out.println("After creating Initable3 ref");
    43         
    44         System.out.println(Initable3.staticNoFinal);
    45         
    46     } 
    47 }

    运行结果如下:

    1 After creating Initable ref
    2 47
    3 Initialzing Initable
    4 258
    5 147
    6 Initializing Initable3
    7 After creating Initable3 ref
    8 74

    这个例子展示了:

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

      2.如果一个static final 值是“编译期常量”,就像Initable.staticFinal那样,那么这个值不需要对Initable类进行初始化话就可以被读取。但是,如果只是将一个域设置为static 和final的,还不足以确保这种行为,例如,对Initable.staticFinal2的访问将强行进行类初始化,因为它不是一个编译期常量。

      3.如果一个static域不是final的,那么在对它进行访问时,总是要求在它被读取之前,要先进行连接(为这个域分配存储空间)和初始化(初始化该存储空间),就像在对Initable.staticNonFinal的访问中看到的那样。

     五、Class对象方法概述:

    1.Class对象概述

      (1)持有RTTI信息

      (2)每个类都有一个Class对象,每当编译一个新类就产生一个Class对象。

      (3) Class引用总是指向某个Class对象。Class引用表示的就是它所指向的对象的确切类型,而该对象便是Class类的一个对象。

    2.forName()

      (1)  获取Class对象的一个引用,但引用的类还没有加载(该类的第一个对象没有生成)就加载了这个类.

      (2)  为了产生Class引用,forName()立即就进行了初始化。

    3.Object-getClass()             获取Class对象的一个引用,返回表示该对象的实际类型的Class引用。

    4.getName()                        获取全限定的类名(包括包名),即类的完整名字。

    5.getSimpleName()              获取类名(不包括包名)

    6.getCanonicalName()          获取全限定的类名(包括包名)

    7.isInterface()                      判断Class对象是否是表示一个接口

    8.getInterface()                   返回Class对象,表示Class对象所引用的类所实现的所有接口。

    9.getSupercalss()                返回Class对象,表示Class对象所引用的类所继承的直接基类。应用该方法可在运行时发现  一个对象完整的继承结构。

    10.newInstance()              返回一个Oject对象,是实现“虚拟构造器”的一种途径。“虚拟构造器”:我不知道你的确切的  类型,但无论如何都要正确创建你自己。用该方法创建的类,必须带有默认的构造器。      

    11.cast()                          接受一个对象为参数,并将其转型为Class引用的类型。该法一般是在无法使用普通转型的情况下使用。    

    12.getClassLoader()          返回该类的类加载器。      

    13.getComponentType()    返回表示数组组件类型的Class。     

    14.isArray()                       判定此 Class 对象是否表示一个数组类。

    15.泛化的Class引用

      1)实现方法:使用通配符“?”。

      2)Class<?>优于Class,即便他们是等价的。

      3)Class<?>的好处是明确地告诉编译器你选择了非具体的类版本,而不是由于碰巧或者疏忽而使用了一个非具体的类引用。

      4)创建一个范围:创建一个Class引用 ,使它被限定为某种类型<className>;或该类型的任何子类型,< ? extends superClass>;或者该类型的超类,< ? super super sunClassName>

  • 相关阅读:
    Spring Boot
    Spring Boot
    Spring Boot
    Restful API
    Jenkins
    虚拟化
    SpringBoot入门
    System Workbench for STM32(based on Eclipse)开发环境配置
    装机总结
    这年暑假
  • 原文地址:https://www.cnblogs.com/yfyzy/p/4398448.html
Copyright © 2011-2022 走看看