Reflection(反射)被视为动态语言的关键,反射机制允许程序在**执行期(Runtime)**借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
框架 = 反射 + 注解 + 设计模式
java.lang.Class
类的加载及反射过程如下
程序经过javac.exe
命令编译以后,会生成一个或多个字节码文件(.class
结尾)。
接着我们使用java.exe
命令对某个字节码文件进行解释运行。字节码文件被ClassLoader加载到JVM内存中,此过程就称为类的加载。加载到内存中的类,我们就称为运行时类(Runtime Class),此运行时类,就作为java.lang.Class
的一个实例。
换句话说,Class的实例只对应着加载到内存中的一个运行时类。
加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类。
一个加载的类在 JVM 中只会有一个Class实例
此时就可以通过Class类的实例方法获取Field
、Method
、Constructor
等实例对象完成反射
方式一:调用运行时类的属性:class
Class clazz = ClassName.class;
方式二:通过运行时类的对象,调用getClass()
方法
Person p = new Person();
Class clazz = p.getClass();
方式三:调用Class的静态方法:forName(String classPath)
,可能抛出ClassNotFoundException
异常
全类名:是
类所属包名 + . + 类名
,例如java.lang.String
Class clazz = Class.forName("全类名");
方式四:使用类的加载器
ClassLoader cl = this.getClass().getClassLoader();
Class clazz = cl.loadClass("全类名");
方式一:构造方法,new Constructor()
方式二:要创建Xxx
类的对象,可以考虑:Xxx
、Xxxs
、XxxFactory
、XxxBuilder
类中查看是否有静态方法的存在。可以调用其静态方法,创建Xxx
对象。
方式三:通过反射
class:类
interface:接口
[]
:数组
enum:枚举
annotation:注解@interface
primitive type:基本数据类型
void
数组的Class实例中,只要类型和维度一样,那么两个Class实例相等
int[] a = new int[10];
int[] b = new int[100];
a.class == b.class
//结果为true
static Class forName(String name)
:根据全类名返回Class对象Object newInstance()
:调用默认无参构造,创建实例getName()
:获取Class所代表的结构全类名get Class[] getInterfaces()
:返回Class对象实现的所有接口的Class对象ClassLoader getClassLoader()
:返回该类的类加载器Class getSuperclass()
:返回Class对象的超类Class对象Constuctor[] getConstrctors()
:返回类的所有构造方法Field[] getDeciaredFields()
:返回所有属性Method getMethod(String name,Class ... paramTypes)
:返回该类中参数为Class ... paramTypes
的方法Package getPackage()
:获取包信息Class<Person> clazz = Person.class;
Person obj = clazz.newInstance();
newInstance()
:调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。
使用此方法,要求:
**不是!**只要在操作的时候明确的调用类中的构造器,并将参数传递进去之后,才可以实例化操作。
getDeclaredConstructor(Class … parameterTypes)
取得本类的指定参数类型的构造器static class Apple{
public Apple(int a){ }
}
public static void main(String[] args) throws Exception {
// 获取Class对象
Class<Apple> appleClass = Apple.class;
// 根据参数获取有参构造
Constructor<Apple> declaredConstructor = appleClass.getDeclaredConstructor(int.class);
// 设置可见性
declaredConstructor.setAccessible(true);
// 创建实例
Apple apple = declaredConstructor.newInstance(1);
}
Class<?>[] getInterfaces()
:获取实现的全部接口Class<? Super T> getSuperclass()
:获取继承的父类Constructor<T>[] getConstructors()
:获取有所public
构造方法Constructor<T>[] getDeclaredConstructors()
:获取所有构造方法int getModifiers()
:获取所有修饰符之和,例如public static
,返回值为1 + 8 = 9
String getName()
:获取方法名称Class<?>[] getParameterTypes()
:获取参数类型修饰符 | 返回值 |
---|---|
public | 1 |
private | 2 |
protected | 4 |
static | 8 |
final | 16 |
synchronized | 32 |
volatile | 64 |
transient | 128 |
native | 256 |
interface | 512 |
abstract | 1024 |
strict | 2048 |
Methos[] getDeclaredMethods()
:获取所有方法Methos[] getMethos()
:获取所有public
方法Class<?> getReturnType()
:获取返回值类型对象Class<?>[] getParameterTypes()
:获取所有参数类型对象int getModifiers()
:获取修饰符Class<?>[] getExceptionTypes()
:获取抛出异常类对象Field[] getFields()
:获取所有public
的属性Field[] getDeclaredFields()
:获取所有属性int getModifiers()
:获取修饰符Class<?> getType()
:获取属性类型对象String getName()
:获取属性名称<A extends Annotation> A getAnnotation(Class<A> annotationClass)
:获取指定类型的注解Annotation[] getAnnotations()
:获取所有注解Type getGenericSuperclass()
:获取父类泛型类型static class MyList extends ArrayList<Number> {
}
public static void main(String[] args) {
Class<MyList> myListClass = MyList.class;
Class<? super MyList> superclass = myListClass.getSuperclass();
System.out.println(superclass.getName()); // java.util.ArrayList
Type genericSuperclass = myListClass.getGenericSuperclass();
System.out.println(genericSuperclass.getTypeName()); // java.util.ArrayList<java.lang.Number>
}
Package getPackage()
:获取所在包public class Person{
private String name;
public Person(String name){
this.name = name;
}
public String show(){
System.out.println(name);
}
}
setAccessible(boolean flag)
方法Method getDeclaredMethod(String name,Class ... parameterTypes)
:获取方法Object invoke(Object obj,Object ... args)
:执行方法null
obj
为null
invoke()
之前,显式的调用setAccessible(true)
设为可访问//一、获取类的Class实例、并获得运行时类的实例
Class clazz = Person.class;
Person p = (Person) clazz.newInstance();
//二、获取需要调用的方法,getDeclaredMethod():
//参数1 :指明获取的方法的名称 参数2:指明获取的方法的形参列表
Method show = clazz.getDeclaredMethod("show", String.class);
//三、保证当前方法可以访问
show.setAccessible(true);
//四、调用方法的invoke()
//参数1:方法的调用者 参数2:给方法形参赋值的实参
//invoke()的返回值即为对应类中调用的方法的返回值。
Object returnValue = show.invoke(p,"CHN");
Class clazz = Person.class;
//创建运行时类的对象
Person p = (Person) clazz.newInstance();
//1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
Field name = clazz.getDeclaredField("name");
//2.保证当前属性是可访问的
name.setAccessible(true);
//3.设置指定对象的此属性值
name.set(p,"Tom");
//4、获取指定对象的此属性值
System.out.println(name.get(p));
Class clazz = Person.class;
//1.获取指定的构造器
//getDeclaredConstructor():参数:指明构造器的参数列表
Constructor constructor = clazz.getDeclaredConstructor(String.class);
//2.保证此构造器是可访问的
constructor.setAccessible(true);
//3.调用此构造器创建运行时类的对象,此时才会进行类加载
Person per = (Person) constructor.newInstance("Tom");