一、java.lang.Class<T>

    在java里,任意一个变量(Field)不是一个引用就是基本的数据类型,而任意一个类都是Object类的直接或间接子类。java.lang.Class<T>也是Object的子类,其实体用来表达程序运行时的classes和interface,也可用来表达enum、array、基本数据类型(boolean, byte, char, short, int, long, float, double)以及关键词void。java反射就是从Class<T>类开始的,Class<T>没有公共的构造方法,却提供了各种在程序运行时获取类的成员变量和类型信息的方法,同时通过Class<T>可以新建一个对象。为了详细谈Class<T>的使用,就不从实例来说,不过这并不影响你对Class<T>认识。在java里,可以通过一下四种方式获取Class<T>对象:

    1、Object.getClass()

    如果能够直接获得某个类的实例,获取Class<T>最直接的方式就是调用getClass()方法。如下:

//获取String的Class<T>对象
Class<?> clazz1 = "java".getClass();		
//获取Console的Class<T>对象		
Class<?> clazz2 = System.console().getClass();

    提示一下:System.comsole()是一个静态方法,返回java.io.Console对象。再看如下代码:

enum E { A, B }
Class clazz = A.getClass();

    因为A是E的一个实例,所以A.getClass()返回的是E的Class<?>对象。再看如下代码:
byte[] bytes = new byte[1024];
Class<?> clazz = bytes.getClass();


    在java里,数值就是一个Object,也就是一个引用,所以上述返回的就是byte数组的Class<T>对象,接着看如下代码:

Set<String> set = new HashSet<String>();
Class<?> clazz = set.getClass();


    如上所示,set实质是HashSet的一个实例,所以set.getClass()返回的是HashSet的Class<T>对象。可问题又来了,如何获得Set的Class<T>对象呢??可以这样做:

Class<?> clazz = java.util.Set.class;


    附:到现在为止,我们一直都是在用Class<?>形式,其与Class<T>有什么区别的呢??“?”是一个匹配字符,匹配任意类型;“T”匹配的是某一具体的类型,如String。如果知道Class的具体类型,可以直接使用Class<T>,如Class<String>。如果想图方便的,可以直接使用Class<?>。

    2、通过属性“.class”获取Class<T>对象

    如果某个对象(属性)不是Object的直接或间接子类(不提供getClass()方法),如interface,基本数据类型。可以通过“.class”属性获取Class<T>对象。

boolean b;
Class<?> clazz = boolean.class;
//注意以下形式无法通过编译
//Class<?> clazz = b.getClass();
//Class<?> clazz = b.class;


    b是一个基本数据类型,不具有getClass()方法,也不具有class属性。再看如下例子:

//获取借口PrintStream的Class对象
Class<?> clazz = java.io.PrintStream.class;
//获取int三维数组的Class对象
Class<?> clazz = int[][][].class;

    因为在java里数组也是一个引用,所以也可以使用以下当时获取int三维数组的Class的对象:

int[][][] number = new int[1][2][3];		
Class<?> clazz = number.getClass();

    除了基本数据类型和接口等,平常用的类也可以通过“.class”属性获取class对象,如下:

    Class<?> clazz = com.entity.User.class;

    3、通过“.TYPE”属性获取Class对象

    对于基本数据类型和接口等,倡导使用”.class”属性获取class对象。不过作为一种知识的完善,在此也提一下通过“.TYPE”属性获取Class对象。java为8种基本数据类型(char,byte,short,int,long,float,double,boolean)和void提供了其对应的wrapper class(包装类/封装类)。在每个wrapper class里有一个属性TYPE,可以用来获取class对象—与”.class”的用法一致。如下:

    Class<?> clazz = Double.TYPE;   //等同于  Class<?> clazz = double.class;

    Class<?> clazz = Void.TYPE;     //等同于  Class<?> clazz = void.class;

 

    4、使用Class.forName(String classpath)方法

    如果知道了类的完整路径,可以通过静态方法Class.forName(String classpath)来多的Class对象,不过Class.forName()不适用基本数据类型,不过数组对象可以使用此方法。如下:

    Class<?> clazz = Class.forName("com.zpq.User");

    Class.forName()在数组里的使用:

Class<?> clazz = Class.forName("[D");
Class<?> clazz = Class.forName("[[Ljava.lang.String;");

    上面的形式可能看起来有点怪,或许偶尔在编译的时候见过这些怪异的字符。在这里解释一下,[  表示一维数组,[[ 二维数组…… L  表示是对象类型,所以第一行返回的是double[]的Class对象,第二行返回的是String[][]的Class对象,在啰嗦一点,如果返回的是对象数组的Class,是需要加”L"和“;”的,如下返回的是User[]的class对象:

    Class<?> clazz1 = Class.forName("[Lcom.zpq.User;");

    类似的,上面获取两个数组的Class对象也可以使用如下形式:

    Class<?> clazz = double[].class;
    Class<?> clazz = String[][].class;

    5.使用Reflection的API获取class对象

    如果可以直接或者间接得获得某个类,那么也可以使用Reflection API获取class对象:

    (1)Class.getSuperclass() — 返回父类的class对象

Class<?> clazz = String.class.getSuperclass();

    因为String的父类是Object,所以此处返回的是Object的class对象。

    (2)Class.getClasses() — 返回一个class对象数组,包含此类里所有公共类与接口(嵌套)

Class<?>[] clazz = Character.class.getClasses();

    嵌套在Character里的公共类有Character.Subset、Character.UnicodeBlock和Character.UnicodeScript。附:Character.UnicodeScript是在java1.7才增加的类,如果是以前的版本,只有Character.Subset、Character.UnicodeBlock。

    (3)Class.getDeclaredClasses() — 返回一个class对象数组,包含此类里所有类与接口(套)

Class<?>[] c = Character.class.getDeclaredClasses();


    返回的class对象数组处理Character.Subset、Character.UnicodeBlock和Character.UnicodeScript,还包含了一个私有的类Character.CharacterCache。

    类似的API还有:

    java.lang.reflect.Field.getDeclaringClass()
    java.lang.reflect.Method.getDeclaringClass()
    java.lang.reflect.Constructor.getDeclaringClass()

    为了更好区分Class.getClasses()和Class.getDeclaredClasses(),可以参考一下下面这个Demo:User.java

public class User {
	
	private static class Post{}
	
	public static class Department{}
	
	public static void main(String[] args){
		Class<?>[] clazz = User.class.getClasses();		//A
//		Class<?>[] clazz = User.class.getDeclaredClasses();	//B
		for (Class<?> class1 : clazz) {
			System.out.println(class1);
		}
	}
}

    A的输入为:image

    B的输出为:image

 

    下一篇将会继续谈到如何获取Class<T>对象的修饰符和类型参数