• Java 编程下简介 Class 与类加载


    即使有一个类并对它一无所知,但其实它本身就包含了许多信息,Java 在需要使用到某个类时才会将类加载,并在 JVM 中以一个 java.lang.Class 的实例存在。从 Calss 实例开始,可以获得类的许多信息。

    Java 在真正需要使用一个类时才会加以加载,而不是在程序启动时就加载所有的类。因为大多数的使用者都只使用到应用程序的部分资源,在需要某些功能时才加载某些资源,可以让系统的资源运用更有效率(Java 本来就是为了资源有限的小型设备而设计的,这样的考虑是必然的)。

    一个 java.lang.Class 对象代表了 Java 应用程序在运行时所加载的类或接口实例,也用来表达 enum(属于类的一种)、annotation(属于接口的一种)、数组、初始类型、void。Class 类没有公开的 构造函数。Class 对象由 JVM 自动产生,每当一个类被加载时,JVM 就自动为其产生一个 Class 对象。

    可以通过 Object 的 getClass() 方法来获得每一个对象对应的 Class 对象,或者是通过 class 常量(Class Literal),在获得 Class 对象之后,就可以操作 Class 对象上的一些公开方法来取得类的基本信息。下面的例子使用 getClass() 方法取得 String 类的 Class 实例,并从中得到 String 的一些基本信息。

    package cn.sunzn.demo;
    
    public class ClassDemo {
    
        @SuppressWarnings("rawtypes")
        public static void main(String[] args) {
            String name = "sunzn";
            Class stringClass = name.getClass();
            System.out.println("类名称:" + stringClass.getName());
            System.out.println("是否为接口:" + stringClass.isInterface());
            System.out.println("是否为基本类型:" + stringClass.isPrimitive());
            System.out.println("是否为数组对象:" + stringClass.isArray());
            System.out.println("父类名称:" + stringClass.getSuperclass().getName());
        }
    
    }

    运行结果如下:

    类名称:java.lang.String
    是否为接口:false
    是否为基本类型:false
    是否为数组对象:false
    父类名称:java.lang.Object

    也可以直接使用以下的方式来取得 String 类的 Class 对象:

    Class stringClass = String.class;

    Java 在真正需要类时才会加载类,所谓真正需要通常指的是要使用指定的类生成对象时(或是使用者指定要加载类时,例如使用 Class.forName() 加载类,或是使用 ClassLoader 的 loadClass() 加载类)。使用类名称来声明参考名称并不会导致类的加载,可以设计一个测试类来印证这个说法。

    package cn.sunzn.demo;
    
    public class TestClass {
    
        static {
            System.out.println("类被载入");
        }
        
    }

    在范例中定义了一个静态区块,默认在类第一次被加载时会运行静态区块(说默认的原因,是因为可以设定加载类时不运行静态区块,使用 Class 生成对象时才运行静态区块)。通过在命令行模式下显示信息,可以了解类何时被加载,可以使用如下的范例来测试类加载时机。

    package cn.sunzn.demo;
    
    public class ClassDemo {
    
        public static void main(String[] args) {
            TestClass test = null;
            System.out.println("声明 TestClass 参考名称");
            test = new TestClass();
            System.out.println("生成 TestClass 实例对象");
        }
    
    }

    运行结果如下:

    声明 TestClass 参考名称
    类被载入
    生成 TestClass 实例对象

    从运行结果中可以看出,声明参考名称并不导致 TestClass 类被加载,而是在使用 new 生成对象时才会加载类。

    Class 的信息是在编译时期就被加入至 .class 文件中,这是 Java 支持运行时期类型识别(Run-Time Type Information 或 Run-Time Type Identification,RTTI)的一种方式:在编译时期编译器会先检查对应的 .class 文件,而运行时期 JVM 在使用某类时,会先检查对应的 Class 对象是否已经加载,如果没有加载,则会寻找对应的 .class 文件并载入。一个类在 JVM 中只会有一个 Class 实例,每个类的实例都会记得自己是由哪个 Class 实例所生成,如下图所示。可以使用 getClass() 或 .class 来取得 Class 实例。

    在 Java 中,数组也是一个对象,也有其对应的 Class 实例。这个对象由具有相同元素与维度的数组所共享,而基本类型像 boolean、byte、char、short、int、long、float、double 和关键词 void,也都有对应的 Class 对象。可以用类常量来取得这些对象。

    package cn.sunzn.demo;
    
    public class ClassDemo {
    
        public static void main(String[] args) {
            System.out.println(boolean.class);
            System.out.println(void.class);
    
            int[] iarr = new int[10];
            System.out.println(iarr.getClass().toString());
    
            double[] darr = new double[10];
            System.out.println(darr.getClass().toString());
        }
    
    }

    运行结果如下:

    boolean
    void
    class [I
    class [D

    在 Java 中数组确实是以对象的形式存在,其对应的类由 JVM 生成。当使用 toString() 来显示数组对象的描述时,[ 表示为数组类型,并加上一个类型代表字,以上的代码运行结果中 I 表示是一个 int 数组,而 D 表示是一个 double 数组。

  • 相关阅读:
    数据结构 -- 栈(一)
    数据结构 -- 栈(二)
    Linux 静态库 & 动态库
    Python及Pycharm安装详细教程
    Makefile研究(三) —— 实际应用
    Makefile研究(二)—— 完整可移植性模板
    Makefile研究 (一)—— 必备语法
    JSON 下 -- jansson 示例
    C语言中的static 详细分析
    Linux 命令 -- tar
  • 原文地址:https://www.cnblogs.com/sunzn/p/3163317.html
Copyright © 2020-2023  润新知