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>

  • 相关阅读:
    EntityFramework优缺点
    领导者与管理者的区别
    七个对我最好的职业建议(精简版)
    The best career advice I’ve received
    Difference between Stored Procedure and Function in SQL Server
    2015年上半年一次通过 信息系统项目管理师
    Difference between WCF and Web API and WCF REST and Web Service
    What’s the difference between data mining and data warehousing?
    What is the difference between a Clustered and Non Clustered Index?
    用new创建函数的过程发生了什么
  • 原文地址:https://www.cnblogs.com/yfyzy/p/4398448.html
Copyright © 2011-2022 走看看