Java反射机制是在运行状态(Runtime)中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,获取它的成员变量;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
包名: java.lang.reflect.*
Java反射机制是Java语言被视为"准动态"语言的关键性质。Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的内部信息(包括其modifiers(诸如public, static等等)、superclass(例如Object)、实现interfaces(例如Serializable),也包括fields和 methods的所有信息),动态地生成此类,并调用其方法或修改其域(甚至是本身声明为private的域或方法)。
主要提供了以下功能:
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理。
1. Object
1.1 Class<?> getClass()
Returns the runtime class of this Object
.
例: KeyBoard k = new KeyBoard();
Class<?> clazz = k.getClass(); 或 Class clazz = k.getClass();
2. Class
Class对象是Java反射的基础,它包含了与类相关的信息,事实上,Class对象就是用来创建类的所有对象的。Class对象是java.lang.Class<T>这个类生成的对象,其中类型参数T表示由此 Class 对象建模的类的类型。例如,String.class的类型是 Class<String>;如果将被建模的类未知,则使用Class<?>。以下是Java API的描述:
Class类的实例表示正在运行的 Java应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象。基本的Java类型(boolean、byte、 char、short、int、long、float和double)和关键字void也表示为Class对象。
Class没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。
每个类都有一个Class对象。换言之,每当编写并且编译了一个新类,就会产生一个Class对象(更恰当的说,是被保存在一个同名的.class文件中)。如果我们想生成这个类的对象,运行这个程序的Java虚拟机(JVM)将使用类加载器子系统,类加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件,并将其载入,一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。
获取Class对象有三种方式:
(1) Object类的getClass()方法,例:
Class c1 = new String("").getClass();
(2) Class类的静态方法forName(),例:
Class c2 = Class.forName(className);
当使用Class.forName()方法时,必须提供完全限定类名。即类名要包括所有包名。
(3) 使用类字面常量或TYPE字段,例:
Class c3 = Manager.class;
Class c4 = int.class;
Class c5 = Double[].class;
这种方式不仅更简单,而且更安全,因为它在编译时就会受到检查,并且根除了对forName方法的调用,也更高效,建议使用“.class”的形式。
TYPE是基本数据类型的包装类型的一个标准字段,它是一个引用,指向对应的基本数据类型的Class对象
使用Java反射,从类中可以获取以下信息:
(1) 类名
(2) 类修饰符 (public, private, synchronized等)
(3) 包信息
(4) 父类
(5) 实现的接口
(6) 构造函数
(7) 方法
(8) 字段
(9) 注解
(10) 内部类
2.1 类名(getName(), getSimpleName())
从Class对象中可以获取两个不同的类名。完全限定类名(包括包名)可以使用getName()或getCanonicalName()方法获取,例如:
Class myClazz = MyObject.class;
String className = myClazz.getName();
String className1 = myClazz.getCanonicalName();
如果想要获取不含包名的类名可以使用getSimpleName() 方法,如下:
String simpleClassName = myClazz.getSimpleName();
2.2 修饰符(getModifiers())
使用Class对象可以获取一个类的修饰符。类的修饰符即关键字"public","private", "static"等. 如下:
int modifiers = myClazz.getModifiers();
修饰符被包装进一个int内,每一个修饰符都是一个标志位(置位或清零)。可以使用java.lang.reflect.Modifier类中的以下方法来检验修饰符:
Modifier.isAbstract(int modifiers)
Modifier.isFinal(int modifiers)
Modifier.isInterface(int modifiers)
Modifier.isNative(int modifiers)
Modifier.isPrivate(int modifiers)
Modifier.isProtected(int modifiers)
Modifier.isPublic(int modifiers)
Modifier.isStatic(int modifiers)
Modifier.isStrict(int modifiers)
Modifier.isSynchronized(int modifiers)
Modifier.isTransient(int modifiers)
Modifier.isVolatile(int modifiers)
2.3 包信息(getPackage())
使用Class对象可以获取包信息java.lang.Package,如下:
Package package = myClazz.getPackage();
String packageName = package.getname();
从Package对象中你可以访问诸如名字等包信息。您还可以访问类路径上这个包位于JAR文件中Manifest这个文件中指定的信息。
2.4 父类(getSuperclass())
通过Class对象可以获取类的父类,如下:
Class superclass = myClazz.getSuperclass();
父类的Class对象和其它Class对象一样是一个Class对象,可以继续使用反射。
2.5 实现的接口(getInterfaces()), 只有给定类声明实现的接口才会返回
通过给定的类可以获取这个类所实现的接口列表,如下:
Class[] interfaces = myClazz.getInterfaces();
一个类可以实现多个接口。因此返回一个Class数组。在Java反射机制中,接口也由Class对象表示。
只有给定类声明实现的接口才会返回。例如,如果类A的父类B实现了一个接口C,但类A并没有声明它也实现了C,那么C不会被返回到数组中。即使类A实际上实现了接口C,因为它的父类B实现了C。
为了得到一个给定的类实现接口的完整列表,需要递归访问类和其超类。
2.6 构造函数
//获取一个公有的构造函数,参数为指定参数 public Constructor<T> getConstructor (Class...<?> parameterTypes) //获取目标类所有的公有构造函数 public Constructor[]<?> getConstructors () // 获取目标类的一个构造函数,参数为指定参数 public Constructor<T> getDeclaredConstructor (Class...<?> parameterTypes) // 获取目标类所有的公有构造函数 public Constructor[]<?> getDeclaredConstructors ()
2.7 方法
这里需要注意的是 getDeclaredMethod 和 getDeclaredMethods 包含private、protected、default、public的函数,并且通过这两个函数获取到的只是在自身中定义的函数,也包括自己实现的接口,从父类和接口中继承的函数不能够获取到。而 getMethod 和 getMethods 只包含 public 函数,父类和接口中继承的公有函数也能够获取到。
//获取该类中的指定参数的某一方法, 可以是private、protected、default、public的, (不包含从父类和接口继承的).
public Method getDeclaredMethod (String name, Class...<?> parameterTypes)
//获取该类中的所有函数(不包含从父类继承的函数). public Method[] getDeclaredMethods () //获取该类指定参数的某一公有函数, (包含从父类和接口类继承下来的) public Method getMethod (String name, Class...<?> parameterTypes) //获取该类所有公有函数, (包含从父类和接口类集成下来的函数) public Method[] getMethods ()
2.8 字段
getDeclaredField 和 getDeclaredFields 包含 private、protected、default、public 的属性,并且通过这两个函数获取到的只是在自身中定义的属性,从父类中集成的属性不能够获取到。而 getField 和 getFields 只包含 public 属性,父类中的公有属性也能够获取到。
// 获取 Class 对象中指定属性名的某一属性
public Method getDeclaredField (String name)
// 获取该 Class 对象中的所有属性( 不包含从父类继承的属性 ) public Method[] getDeclaredFields () // 获取指定的Class对象中指定属性名的某一公有属性 public Method getField (String name) // 获取该Class对象中的所有公有属性 ( 包含从父类和接口类继承下来的公有属性 ) public Method[] getFields ()
2.9 注解
// 获取该类某一指定公有注解 public <A extends Annotation> A getAnnotation(Class<A> annotationClass) // 获取该类所有公有注解 public Annotation[] getAnnotations() // 获取该类某一注解 public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) // 获取该类所有注解 public Annotation[] getDeclaredAnnotations()
2.10 内部类
// 获取该类公有内部类(包含父类) public Class<?>[] getClasses() // 获取该类所有内部类,包含私有内部类。 public Class<?>[] getDeclaredClasses() // 获取该类的外部类 public Class<?> getDeclaringClass()
2.11 其它方法
// ([自身类.class]).isAssignableFrom([自身类.class]或[其子类.class]) 返回true
isAssignableFrom(Class<?> cls)
// ([自身类.class]).isInstance([自身类的实例obj]或[其子类的实例obj]) 返回true
isInstance(Object obj)
// 这里不是Class成员方法,是一个运算符,放在这里一起比较;
// [实例obj] instanceof [自身类、其父类、抽象类或接口],右边使用的是简单类名,而不是Class。
instanceof
// 生成本类的对象,只能调用无参构造。我们使用new的时候,这个要new的类可以没有加载。使用newInstance时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。Class的静态方法forName()调用了启动类加载器(就是加载javaAPI的那个加载器)。newInstance实际上是把new这个方式分解为两步,即,首先调用class的加载方法加载某个类,然后实例化。这样分步的好处是显而易见的。我们可以在调用Class的静态加载方法forName()时获得更好的灵活性(传入的className可以是从任何地方获取的),提供给了我们降耦的手段。
newInstance()
// 返回当前clazz是否为成员类;
isMemberClass()
// 返回当前类是否为接口;
isInterface()
3. Constructor
// 返回当前Constructor实例所在的Class.
Class<T> getDeclaringClass()
// 返回当前Constructor实例参数个数.
int getParameterCount()
// 返回当前Constructor实例各参数对应的Class类型.
Class<?>[] getParameterTypes()
// 返回当前Constructor实例的各参数类型.
TypeVariable<Constructor<T>>[] getTypeParameters()
// 返回当前Constructor实例对应的方法修饰符.
int getModifiers()
// 返回当前方法名.
String getName()
// 使用当前Constructor实例构造一个该Constructor实例所在的Class的实例,相当于调用其对应参数个数的构造方法.
T newInstance(Object... initargs)
4. Field
// 返回指定对象obj上Field对象表示的字段的值。
Object get(Object obj)
// 将指定对象变量obj上此Field对象表示的字段设置为指定的新值。
void set(Object obj, Object value)
// 返回一个Class对象,它标识了此Field对象所表示字段的声明类型。
Class<?> getType()
// 返回表示类或接口的Class对象,该类或接口声明了由此Field对象表示的字段。
Class<?> getDeclaringClass()
// 返回此Field对象表示的字段的名称。
String getName()
// 以整数形式返回由此Field对象表示的字段的 Java 语言修饰符。
int getModifiers()
5. Method
// 以指定参数调用obj对象的此Method所表示的方法。
Object invoke(Object obj, Object... args)
// 返回此Method实例参数个数.
int getParameterCount()
// 返回此Method实例各参数对应的Class类型.
Class<?>[] getParameterTypes()
// 返回此Method实例的各参数类型.
TypeVariable<Constructor<T>>[] getTypeParameters()
// 返回此Method实例的返回值类型.
Class<?> getReturnType()
// 返回表示类或接口的Class对象,该类或接口声明了由此Method对象表示的方法。
Class<?> getDeclaringClass()
// 返回此Method对象表示的方法的名称。
String getName()
// 以整数形式返回由此Method对象表示的方法的 Java 语言修饰符。
int getModifiers()