认识Class类
Java反射的源头是Class类,若想完成反射操作,首先必须认识Class类。一般情况下,需要先有一个类的完整路径引入之后,才可以按照固定的格式产生实例化对象,但是在Java中允许通过一个实例化对象找到一个类的完整信息,这就是Class类的功能。
为了帮助大家快速了解什么是反射以及Class类的作用,接下来,通过一个案例来演示如何通过对象得到完整的“包.类”名称,如例1所示。
例1 GetClassNameDemo.java
1 package cn.itcast.chapter08.javabean;
2 class X{}
3 public class GetClassNameDemo {
4 public static void main(String[] args) {
5 X x = new X();
6 System.out.println(x.getClass().getName());
7 }
8 }
运行结果如图1所示。
图1 运行结果
从图1中可以看出,程序输出了对象所在的完整的“包.类”名称。在例1中通过对象的引用x调用了getClass()方法,这个是从Object类中继承而来的,此方法的定义如下:
public final Class<?> getClass()
从上述定义可以看出,该方法返回值的类型是一个Class类类型。这是因为Java中Object类是所有类的父类,所以,任何类的对象都可以通过调用getClass()方法转变成Class类型来表示。需要注意的是,在定义Class类时使用了泛型声明,若想避免程序出现警告信息,可以在泛型宗指定操作的具体类型。 Class类表示一个类的本身,通过Class可以完整地得到一个类中的结构,包括此类中的方法定义、属性定义等等。接下来列举一下Class类的一些常用方法,具体如表1所示。
表1 Class类的常用方法
方法声明 | 功能描述 |
---|---|
static Class<?> forName(String className) | 返回与带有给定字符串名的类或接口相关联的Class对象。 |
Constructor<?>[] getConstructors() | 返回一个包含某些 Constructor 对象的数组,这些对象反映此Class对象所表示的类的所有公共构造方法。 |
Field[]getDeclaredField(String name) | 返回Field对象的一个数组,这些对象反映此Class对象所表示的类或接口所声明的所有字段。包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段。 |
Field[]getFields() | 返回一个包含某些Field对象的数组,这些对象反映此Class对象所表示的类或接口的所有可访问公共字段,包括继承的公共字段。 |
Method[]getMethods() | 返回一个包含某些Method对象的数组,这些对象反映此 Class对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共成员方法。 |
Method getMethod(String name, Class<?>... parameterTypes) | 返回一个Method对象,反映此Class对象所表示的类或接口的指定公共成员方法。 |
Class<?>[] getInterfaces() | 返回该类所实现的接口的一个数组。确定此对象所表示的类或接口实现的接口。 |
String getName() | 以String的形式返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称。 |
Package getPackage() | 获取此类的包。 |
Class<? super T> getSuperclass() | 返回表示此Class所表示的实体(类、接口、基本类型或void)的超类的Class。 |
T newInstance() | 创建此Class对象所表示的类的一个新实例。 |
boolean isArray() | 判定此Class对象是否表示一个数组类。 |
表1中,大部分方法都用于获取一个类的结构,这些常用方法是掌握反射技术的基础,因此灵活运用这些方法就显得尤为重要。
在Class类中本身没有定义任何的构造方法,因此不能通过new直接创建Class类的实例。获得Class类的实例有三种方式,具体如下:
● 通过“对象.getClass()”方式获取该对象的Class实例
● 通过Class类的静态方法forName(),用类的全路径名获取一个Class实例
● 通过“类名.class”的方式来获取Class实例,对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例
需要注意的是,通过Class类的forName()方法相比其他两种具有灵活性,其他两种都需要明确一个类,如果一个类操作不确定时,使用起来可能会受一些限制。但是forName()方法只需要以字符串的方式传入即可,这样就让程序具备更大的灵活性,所以它也是三种方式中最常用的。