在Java语言当中,有一个java.lang.Class类,这个类有点“特殊”。不可否认,java.lang.Class类是一种类型;但是,java.lang.Class类与普通类(例如Integer、String等)是不同的。
在本文当中,对java.lang.Class类的讨论分为4个部分:前2个部分是讲java.lang.Class与普通类的区别,第3个部分是如何获取java.lang.Class类的对象和简单的使用,第4部分是对于java.lang.Class类的forClass方法进行一个小小的深入讨论。
1、java.lang.Class类的创建者
java.lang.Class类的创建者是“Java Virtual Machine(JVM)”,而普通类(例如Integer、String等)的创建者是“程序开发人员”。
普通类是由程序开发人员使用的,以String类为例,代码如下:
public static void main(String[] args) { String str = new String("Hello World"); System.out.println(str.length()); }
而java.lang.Class类的创建则是由JVM来完成的,对于java.lang.Class的描述中有一段是这样的:
Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.
由上面这段描述可知,java.lang.Class类是没有公共构造函数的(Class has no public constructor),它由JVM调用(Class objects are constructed automatically by the Java Virtual Machine)。下面是java.lang.Class类的构造函数的源代码:
/* * Constructor. Only the Java Virtual Machine creates Class * objects. */ private Class() {}
值得注意的是:java.lang.Class的实例,虽然由JVM来创建,但是并不代表“该实例只能由JVM使用”。换句话说,由JVM创建java.lang.Class实例,接下来程序开发人员对该实例进行使用。
在本小节当中,主要是讲java.lang.Class的实例是由JVM创建的,与其它普通类(例如Integer、String是由程序开发人员创建的)不同,在明白了这样一个前提下,我们接下来看一看java.lang.Class到底有什么特别的作用。
2、java.lang.Class类的作用
不可否认,java.lang.Class类是一种数据类型(Type)。
但是,从上一节可以得知:java.lang.Class类的实例由JVM创建,而普通类的实例则由程序员进行创建。那么,java.lang.Class这种特殊的实例构建方法,究竟是为了什么呢,又或者说,它可以带来什么作用呢?
让我们做这样一个假设:如果对一件东西进行了特别的处理,那么那件东西一定具有特殊性。接下来,就让我们看看java.lang.Class类有什么特殊的地方:
我们都知道,Integer用来描述一个整数,String类可以用来描述一个字符串,而java.lang.Class可以对Integer、String等类型进行描述。换句话说,Integer、String用来描述一种数据类型,而java.lang.Class则是对“Integer、String等类型”进行描述的类型。读起来,有些拗口,多读三遍。
下面是一段对java.lang.Class的描述:
Instances of the class Class represent classes and interfaces in a running Java application.
在这里,只需要了解java.lang.Class类是用来描述“Integer、String等类型”的相关信息的,就可以了;而不必详尽的知道这些信息的具体内容。
3、获取java.lang.Class类的实例和简单使用
在面向对象的语言中,要使用一个东西,那么就要先获取到它。那么,在这里就是:要想使用java.lang.Class类的实例,就要先获得到java.lang.Class的实例。
3.1、获取java.lang.Class类的实例
有两种方式来获得java.lang.Class类的实例。
一种是通过普通类实例,调用其getClass()方法代码如下:
static void printClassName(Object obj) { Class<?> cls = obj.getClass(); String clsName = cls.getName(); System.out.println(clsName); }
下面是调用方法:
public static void main(String[] args) { String str = new String("Hello world"); printClassName(str); Integer iNumber = new Integer(10); printClassName(iNumber); }
下面是输出的结果:
java.lang.String java.lang.Integer
另一种是通过普通类的类名直接调用其class常量成员,
String类型代码如下:
public static void main(String[] args) { Class<?> cls = String.class; System.out.println(cls.getName()); }
Integer类型代码如下:
public static void main(String[] args) { Class<?> cls = Integer.class; System.out.println(cls.getName()); }
3.2、简单使用java.lang.Class类
4、forClass方法的初始化
在java.lang.Class类中,有一个静态方法:
public static Class<?> forName(String className)
这个方法的功能如下:
Returns the Class object associated with the class or interface with the given string name.
除了上面的描述外,下面这句话引起了我的注意:
A call to forName("X") causes the class named X to be initialized.
它的意思是说,调用forName("X")会让名字为“X”的类进行初始化(initialized)。
我对“initialized”这个词产生了好奇:它要进行初始化(initialize),究竟要做什么工作呢?
针对这个问题,我设计一个StatisticMethod类:
package com.rk.properties; public class StatisticMethod { //001 public static double PI = getPI(); //002 static { System.out.println("静态代码段"); PI = getSecondPI(); } static double getPI() { System.out.println("static void getPI()"); return 3.14; } static double getSecondPI() { System.out.println("static double getSecondPI()"); return 6.28; } public StatisticMethod() { System.out.println("public StatisticMethod()"); } }
接下来,我用Class.forName()方法对StatisticMethod类进行了调用,代码如下:
public static void main(String[] args) { try { Class<?> cls = Class.forName("com.rk.properties.StatisticMethod"); System.out.println(cls.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
执行结果如下:
static void getPI() 静态代码段 static double getSecondPI() com.rk.properties.StatisticMethod
结果分析:
第一被调用的是:
public static double PI = getPI();
第二被调用的是静态代码段:
static { System.out.println("静态代码段"); PI = getSecondPI(); }
值得注意的是,并没有调用构造函数,所以Class.forName()只是对静态变量和静态代码段进行了初始化(initialize),并没有生成类的实例对象。