什么是反射
java的反射机制可以说也是java比较核心的部分,及通过字节码文件来创建对象,访问其成员变量和调用其成员方法。且这种访问无论该对象是否私有都能被访问到,也被称作暴力访问。这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。当类被编译后,JVM将对其生成.class文件,也就是字节码文件,该文件包含了所对应类的信息,当然是以二进制的方法进行存储的,由JVM分析,识别,和执行。
反射获取字节码对象
(1)创建一个类用于测试
使其构造方法,成员变量,方法都为私有的
public class Cat{
private Cat(String name){
this.name = name;
}
private int age;
private String name;
private void printName(String frame){
System.out.println(frame+":"+name);
}
}
(2)获取Class(字节码)对象的三种方法
public class Reflect {
public static void main(String[] args){
//通过类的对象获取字节码对象
Cat cat = new Cat();
Class class1 = cat.getClass();
//通过类的.class获取字节码对象
Class class2 = Cat.class;
//通过名字查找字节码对象(名字为该类的全路径)
Class class3;
{
try {
class3 = Class.forName("com.company.Cat");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
类与class类对应的对象
class类是java中一个较为特殊的类,其包含了描述变量的Field,描述方法的Method,描述构造方法的Constructor,class类只能由系统创建,且每个java类都对应了一个class对象,有且仅有一个(及一个类在JVM中只对应一个class对象)。
reflec反射API中的四个核心类:
- Class类:反射的核心类,可以获取构造方法,方法,成员变量等,可暴力访问任何类。
- Field类:Java.lang.reflec包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
- Method类: Java.lang.reflec包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。
- Constructor类: Java.lang.reflec包中的类,表示类的构造方法。
反射的应用
字节码对象拥有两个方法getDeclaredConstructor()和getConstructor(),getConstructor()是不可以访问除public以外的其他对象的,getDeclaredConstructor()则可以暴力访问,但是需要调用setAccessible()方法设置其值为ture,才能暴力访问。
(1)使用反射获取对象
public class Reflect {
public static void main(String[] args){
Class CatClass = Cat.class;
try {
Constructor constructor = CatClass.getDeclaredConstructor(String.class);
constructor.setAccessible(true);//暴力访问
Cat cat = (Cat) constructor.newInstance("小白");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
(2)使用反射获取成员变量并修改其值
public class Reflect {
public static void main(String[] args){
Class CatClass = Cat.class;
try {
//如果该类的对象的构造方法不是私有的也可以直接new出对象来
Constructor constructor = CatClass.getDeclaredConstructor(String.class);
constructor.setAccessible(true);//暴力访问
Cat cat = (Cat) constructor.newInstance("小白");
Field[] fs = CatClass.getDeclaredFields();
for(Field f:fs){
System.out.println(f);
}
//获取成员变量,传入成员变量的值
Field field = CatClass.getDeclaredField("name");
//给成员变量赋值
field.setAccessible(true);//暴力访问
//第一个参数表示该成员所属与哪个类,第二个参数为设置的值
field.set(cat,"小黑");
//读取Field值
System.out.println(field.get(cat));
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
(3)使用反射获取成员方法并调用
public class Reflect {
public static void main(String[] args){
Class CatClass = Cat.class;
try {
//如果该类的对象的构造方法不是私有的也可以直接new出对象来
Constructor constructor = CatClass.getDeclaredConstructor(String.class);
constructor.setAccessible(true);//暴力访问
Cat cat = (Cat) constructor.newInstance("小白");
//获取方法 第一个参数为方法名,其后的参数为调用方法所需要传入的参数
Method method = CatClass.getDeclaredMethod("printName",String.class);
method.setAccessible(true);
method.invoke(cat,"暴力访问");
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
Class类所包含的重要方法
class类中很多方法对应了一个Declared方法,其无论获取对象是否私有均可访问
获取内容 | 方法签名 |
---|---|
获取构造器 |
|
包含的方法 |
|
获取成员变量 |
|
包含的Annotation | <A extends Annotation> A getAnnotation(Class<A> annotationClass) |
内部类 | Class<?>[] getDeclaredClasses() |
外部类 | Class<?> getDeclaringClass() |
所实现的接口 | Class<?>[] getInterfaces() |
修饰符 | int getModifiers() |
获取所在包 | Package getPackage() |
获取类名 | String getName() |
获取简称 | String getSimpleName() |