该Java教程是为JDK 8编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,可能使用不再可用的技术。
有关Java SE 9和后续版本中更新的语言特性的摘要,请参阅Java语言更改。
有关所有JDK版本的新功能、增强功能以及已删除或弃用选项的信息,请参阅JDK发行说明。
所有反射操作的入口点是java.lang.Class
。除了java.lang.reflect.ReflectPermission
之外,java.lang.reflect
中的其他类都没有公共构造函数。要访问这些类,需要在Class
上调用适当的方法。可以通过对象实例、类名、类型或现有的Class
来获取Class
。
如果有一个对象的实例可用,那么最简单的获取其Class
的方法是调用Object.getClass()
。当然,这只适用于继承自Object
的引用类型。以下是一些示例。
Class c = "foo".getClass();
Class c = System.console().getClass();
虚拟机关联了一个唯一的控制台,可以通过静态方法System.console()
返回。由getClass()
返回的值是与java.io.Console
对应的Class
。
enum E { A, B } Class c = A.getClass();
A
是枚举类型E
的一个实例;因此,getClass()
返回与枚举类型E
相对应的Class
。
byte[] bytes = new byte[1024]; Class c = bytes.getClass();
由于数组是Objects
,因此也可以在数组的实例上调用getClass()
。返回的Class
对应于具有组件类型byte
的数组。
import java.util.HashSet; import java.util.Set; Set<String> s = new HashSet<String>(); Class c = s.getClass();
在这种情况下,java.util.Set
是java.util.HashSet
类型的对象的接口。由getClass()
返回的值是对应于java.util.HashSet
的类。
如果类型是可用的但没有实例,则可以通过将".class"
附加到类型的名称来获取Class
。这也是获取原始类型的Class
的最简单方法。
boolean b; Class c = b.getClass(); // 编译时错误 Class c = boolean.class; // 正确
请注意,语句boolean.getClass()
会产生编译时错误,因为boolean
是原始类型,不能被引用。而.class
语法返回对应于类型boolean
的Class
。
Class c = java.io.PrintStream.class;
变量c
将是与类型java.io.PrintStream
对应的Class
。
Class c = int[][][].class;
使用.class
语法可以获取给定类型的多维数组对应的Class
。
如果类的全限定名可用,可以使用静态方法Class.forName()
来获取相应的Class
。但是这不能用于基本类型。数组类的名称语法由Class.getName()
描述。这个语法适用于引用类型和基本类型。
Class c = Class.forName("com.duke.MyLocaleServiceProvider");
这个语句将根据给定的全限定名创建一个类。
Class cDoubleArray = Class.forName("[D"); Class cStringArray = Class.forName("[[Ljava.lang.String;");
变量cDoubleArray
将包含与基本类型double
的数组对应的Class
(与double[].class
相同)。变量cStringArray
将包含与二维数组String
对应的Class
(与String[][].class
相同)。
.class
语法是获取原始类型的Class
的更方便和首选方式;然而,还有另一种获取Class
的方法。每个原始类型和void
在java.lang
中都有一个包装类,用于将原始类型装箱为引用类型。每个包装类都包含一个名为TYPE
的字段,该字段等于被包装的原始类型的Class
。
Class c = Double.TYPE;
有一个类java.lang.Double
,用于封装基本类型double
,当需要一个Object
时使用。 Double.TYPE
的值与double.class
相同。
Class c = Void.TYPE;
Void.TYPE
与void.class
相同。
有几个反射API返回类,但只有在已经直接或间接地获取到Class
的情况下才能访问。
Class.getSuperclass()
Class c = javax.swing.JButton.class.getSuperclass();
javax.swing.JButton
的父类是javax.swing.AbstractButton
。
Class.getClasses()
Class<?>[] c = Character.class.getClasses();
Character
包含两个成员类Character.Subset
和Character.UnicodeBlock
。
Class.getDeclaredClasses()
Class<?>[] c = Character.class.getDeclaredClasses();
Character
包含两个公共成员类Character.Subset
和Character.UnicodeBlock
,以及一个私有类Character.CharacterCache
。
Class.getDeclaringClass()
java.lang.reflect.Field.getDeclaringClass()
java.lang.reflect.Method.getDeclaringClass()
java.lang.reflect.Constructor.getDeclaringClass()
Class
。匿名类声明没有声明的类,但有一个封闭的类。
import java.lang.reflect.Field; Field f = System.class.getField("out"); Class c = f.getDeclaringClass();
out
在System
中声明。
public class MyClass { static Object o = new Object() { public void m() {} }; static Class<c> = o.getClass().getEnclosingClass(); }
o
定义的匿名类的声明类为null
。
Class.getEnclosingClass()
Class c = Thread.State.class().getEnclosingClass();
Thread.State
的封闭类为Thread
。
public class MyClass { static Object o = new Object() { public void m() {} }; static Class<c> = o.getClass().getEnclosingClass(); }
o
定义的匿名类被MyClass
封闭。