Java反射
什么是Java的反射机制?
java反射就是在运行状态中,对于任意一个类都知道这个类的所有属性和方法;对于任何一个对象都能调用它的属性和方法,这种动态调用对象的方法、获取类的信息的功能称为Java语言的反射机制。
优点:运行时期动态加载类,和类的判断,提高了代码的灵活性。
缺点:反射相当于一系列解释的操作,通知jvm要做的事情,性能比直接Java代码慢。
如何实现反射?
package com.reflection;
public class GetClass {
public static void main(String[] args) {
//方法一 通过创建的对象
Student student = new Student();
Class<? extends Student> aClass1 = student.getClass();//获取运行时类
//方法二 通过相对路径,包名.类名
try {
Class<?> aClass2 = Class.forName("com.reflection.Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//方法三 通过类名
Class<Student> aClass3 = Student.class;
}
}
class Student {
private String name;
private int age;
private String sex;
}
注意:一个类在JVM中只有一个Class实例,所以上面这三个Class实例调用equals()方法结果为true。
通过反射去调用方法和属性
package com.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @Description 反射机制
* @author RAy-LlT
* @date 2021/8/24 15:37
*/
public class GetClass {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class<Student> aClass = Student.class;
//获取类名称com.Reflection.Student
aClass.getName();
//获取类及其父类中的所有public属性
Field[] fields = aClass.getFields();
//获取指定public类型的属性,也就是fields中包含的属性
Field age = aClass.getField("age");
//获取该类中声明所有类型的属性
Field[] declaredFields = aClass.getDeclaredFields();
//获取指定的属性,也就是declaredFields中包含的属性
Field name = aClass.getDeclaredField("name");
//通过类的不带参数的构造方法创建这个类的一个对象,因此要想在任意地方直接通过此方法去实例化,那么你的修饰符必须为public
Student student = aClass.newInstance();
//获得类的public类型的构造方法
Constructor<?>[] constructors = aClass.getConstructors();
//获取指定的构造方法(public),此处获取的为private类型,所以会抛出NoSuchMethodException异常
try {
Constructor<Student> constructor1 = aClass.getConstructor(String.class, int.class, String.class);
} catch (NoSuchMethodException e) {
System.out.println(e);
}
//获取所有类型的构造方法
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
//获取指定的任意构造方法
Constructor<Student> declaredConstructor = aClass.getDeclaredConstructor(String.class, int.class, String.class);
//值为true则指示反射的对象在使用是应该取消Java语言访问检查,就可以暴力调用私有方法进行实例化
declaredConstructor.setAccessible(true);
//此处的student实例并不能访问其私有类型的属性,除非设置私有属性取消java语言的访问检查
Student student1 = declaredConstructor.newInstance("碎涛", 21, "男");
//通过反射生成的实例,只能直接 对象.它的public属性和方法,其他的只能单独去获取,设置其取消java语言的访问检查
student1.age = 20;
name.setAccessible(true);
name.set(student1, "java长征记");
name.get(student1);
//获取Student类的public方法以及其所继承的父类的public方法,当然也包括Object类中的一些方法
Method[] methods = aClass.getMethods();
//获取指定的public类型的方法,也就是上面methods中的所有方法
Method print1 = aClass.getMethod("print1", int.class);
//调用invoke( )方法执行获取到的方法
print1.invoke(student1, 1314);
//获取该类中声明的除构造方法之外的所有方法,不包含父类
Method[] declaredMethods = aClass.getDeclaredMethods();
//获取指定的任意类型的方法(该类中),也就是上面declaredMethods中包含的方法
Method print2 = aClass.getDeclaredMethod("print2", String.class);
//获取其父类,想获取其父类的的私有属性和方法就可以先获取其父类Class实例,然后再去按照上面的方法获取就可以了
Class<? super Student> superclass = aClass.getSuperclass();
}
}
class Person {
private String birth;
public int height;
protected int weight;
public void ppp() {
System.out.println("WX搜索:java长征记");
}
protected void aaa() {
System.out.println("WX搜索:java长征记");
}
private String lll() {
return "WX搜索:java长征记";
}
}
class Student extends Person {
private String name;
public int age;
private String sex;
public Student() {
System.out.println("public 无参构造方法");
}
private Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
System.out.println("private 有参的构造方法");
}
public void print1(int a) {
System.out.println(a);
}
private void print2(String s) {
System.out.println(s);
}
}
注意:使用反射可以打破封装性,导致了Java对象的属性不安全。因此,String类中的对象不可变其实是可以通过反射去改变的。
package com.reflection;
import java.lang.reflect.Field;
/**
* @Description 反射修改String对象不可变
* @Author RAy-LlT
* @Date 2021/11/18 14:40
*/
public class ChangeString {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
//创建字符串"Hello World", 并赋给引用s
String s = "Hello World";
System.out.println("s=" + s);//s = Hello World
// 获取String类中的value字段
Field valueFieldOfString = String.class.getDeclaredField("value");
// 改变value属性的访问权限
valueFieldOfString.setAccessible(true);
// 获取s对象上的value属性的值
char[] value = (char[]) valueFieldOfString.get(s);
// 改变value所引用的数组中的第5个字符
value[5] = '_';
System.out.println("s = " + s); // s = Hello_World
}
}
反射的应用场景
1.加载数据库的驱动;
Class.forName("com.mysql.jdbc.Driver");
2.获取对象的属性,方法,类和类的构造方法等;
3.instanceof 关键字是通过反射来实现的;
4.IDEA、Eclipse在输入“.”之后会自动弹出相应的方法和属性,是通过反射来实现的;
5.Spring框架里面的xml装配文件等。