反射
反射允许对成员变量,成员方法和构造方法的编程访问
IDEA中的形参提示,方法列出,都是利用反射实现的。
即:反射可以从类中,获取成员变量,成员方法,构造方法。
获取class对象 : Class
构造方法: Constructor
字段(成员变量): Field
成员方法: Method
样例Student类:
package MyReflectDemo1;
public class Student {
private String name;
private int age;
public String gender;
public Student(){
}
public Student(String name, int age ,String gender) {
this.name = name;
this.age = age;
this.gender=gender;
}
private Student(String name){
this.name = name;
}
protected Student(int age){
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setGender(String gender){
this.gender=gender;
}
public String getGender(){
return gender;
}
public void study() {
System.out.println(name + "正在学习");
}
private void play(){
System.out.println("正在部署爆能器");
}
protected void sleep(){
System.out.println("正在睡觉");
}
public String eat(String food) throws NullPointerException{
System.out.println("在吃" + food);
return "吃饱辣";
}
public void eat(String food, String water) {
System.out.println("在吃" + food + "喝" + water);
}
}
获取class对象的三种方式
public class MyReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
//Class.forName(全类名)方法获取class文件,全类名:包名+类名
Class clazz1 = Class.forName("MyReflectDemo1.Student");//最常用
System.out.println(clazz1);
//类名.class
Class clazz2 = Student.class;//常作为参数使用
// 如 : synchronized (clazz2)
//对象.getClass()
//当已经有了这个类的对象时,才可以使用
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz3 == clazz1);
System.out.println(clazz3 == clazz1);
//获取到的class对象是同一个
}
}
反射获取构造方法
public class MyReflectDemo1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class clazz1 = Class.forName("MyReflectDemo1.Student");
//获取到的class对象是同一个
//获取构造方法(需获取class字节码文件)
Constructor[] cons = clazz1.getConstructors();//获取所有公有的构造方法
for(Constructor con : cons)
{
System.out.println(con);
}
//获取所有构造方法(包括公有,私有,保护)
Constructor[] declaredConstructors = clazz1.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
Constructor con = clazz1.getDeclaredConstructor();//获取空参的一个构造方法
System.out.println(con);
Constructor con1 = clazz1.getDeclaredConstructor(String.class, int.class);//获取有参的构造方法
System.out.println(con1);
Constructor constructor = clazz1.getConstructor();//获取空参的一个公有构造方法
System.out.println(constructor);
Constructor constructor1 = clazz1.getConstructor(String.class, int.class);//获取有参的公有构造方法
System.out.println(constructor1);
//获取构造方法的修饰符
int modifiers = constructor1.getModifiers();
System.out.println(modifiers);
//获取构造方法的参数
Parameter[] parameters = con1.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
//暴力反射
//利用反射强行调用私有方法创建对象(即自动装配原理,底层暴力反射)
con1.setAccessible(true);//临时取消权限校验:获取构造方法只是显现,依然无法直接访问,需要取消权限校验
Student yg = (Student) con1.newInstance("杨光", 19);
System.out.println(yg);
}
}
getModifiers()方法可以获取修饰符,但不是以字符串形式展现,是以整数类型展现。
abstract : 1024 Final: 16 interface: 512 private : 2
public: 1 static: 8 等等
反射获取成员变量
public class MyReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class clazz = Class.forName("MyReflectDemo1.Student");
//获取所有成员变量
Field[] declaredFields = clazz.getDeclaredFields();
for(Field field : declaredFields){
System.out.println(field);
}
System.out.println("----------------芝士分割线------------------");
//获取所有公共成员变量
Field[] fields = clazz.getFields();
for(Field field : fields){
System.out.println(field);
}
System.out.println("----------------芝士分割线------------------");
//获取指定成员变量(公共修饰符)
Field gender1 = clazz.getField("gender");
System.out.println(gender1);
//获取指定成员变量(所有修饰符)
Field name = clazz.getDeclaredField("name");
System.out.println(name);
//获取成员变量的修饰符
int modifiers = name.getModifiers();
System.out.println(modifiers);
//获取成员变量的类型
String name1 = name.getName();
System.out.println(name1);
//获取成员变量的类型
Class<?> type = name.getType();
System.out.println(type);
System.out.println("----------------芝士分割线------------------");
Student stu = new Student("佟gt",19,"男");
//获取成员变量记录的值
name.setAccessible(true);//临时取消权限校验,暴力反射获取
Object o = name.get(stu);
System.out.println(o);
System.out.println("----------------芝士分割线------------------");
//修改成员变量的值
name.set(stu,"魔法少女tgt");
gender1.setAccessible(true);
gender1.set(stu,"沃尔沃塑料袋");
String newName = stu.getName();
String newGender = stu.getGender();
System.out.println(newName);
System.out.println(newGender);
}
}
反射获取成员方法
public class MyReflectDemo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = Class.forName("MyReflectDemo1.Student");
//获取所有公有的成员方法(包含父类中的方法)
Method[] methods = clazz.getMethods();
for(Method method : methods){
System.out.println(method);
}
System.out.println("----------------芝士分割线------------------");
//获取所有的方法(不能获取父类中的方法)
Method[] methods1 = clazz.getDeclaredMethods();
for (Method method : methods1){
System.out.println(method);
}
System.out.println("----------------芝士分割线------------------");
//获取指定名称的方法
//若出现方法重名,则还需仔细指定参数列表
Method eat1 = clazz.getDeclaredMethod("eat", String.class);
System.out.println(eat1);
Method eat2 = clazz.getDeclaredMethod("eat", String.class, String.class);
System.out.println(eat2);
System.out.println("----------------芝士分割线------------------");
//获取指定名称的私有方法
Method play = clazz.getDeclaredMethod("play");
System.out.println(play);
//获取指定名称的公有方法
Method m = clazz.getMethod("study");
System.out.println(m);
System.out.println("----------------芝士分割线------------------");
//获取方法名
String methodName = m.getName();
System.out.println(methodName);
//获取方法的参数信息
int parameterCount = eat2.getParameterCount();//方法的参数数量
Class<?>[] parameterTypes = eat2.getParameterTypes();//方法参数的类型
//直接获取参数
Parameter[] parameters = eat2.getParameters();
for (Parameter parameter : parameters){
System.out.println(parameter);
}
//获取方法抛出的异常
Class<?>[] exceptionTypes = eat2.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes){
System.out.println(exceptionType);
}
//获取方法的修饰符
int modifiers = eat2.getModifiers();
System.out.println(modifiers);
System.out.println("----------------芝士分割线------------------");
//调用方法
Student s = new Student();
//s:方法的调用者,后面是方法参数
//接收返回值
Object o =eat1.invoke(s, "铁牛牛肉面");
System.out.println(o);
}
}
总结
反射可以获取一个类里面所有信息,获取到后,再执行其他业务逻辑。
结合配置文件,动态的创建对象并调用方法。