java反射
概念:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
用途
用途广泛,列入拦截器,aop,自定义注解等可以参考
代码使用
(一个类只有一个class文件) clazz.newInstance() 就是获取对象
//一、通过反射获取类
//1、获取对象的class 个人认为没啥鸟用
Class<? extends Student> aClass = new Student().getClass();
//2、通过类.class
Class<Student> studentClass = Student.class;
//3、通过Class.forName
Class<?> aClass1 = Class.forName("com.zhk.study.Student");
System.out.println(aClass == studentClass && aClass == aClass);//true
//二、通过反射获取构造方法并使用:
//1.加载Class对象
Class clazz = Class.forName("com.zhk.study.Student");
//2、获取所有构造方法(公有)
Constructor[] constructors = clazz.getConstructors();
Stream.of(constructors).forEach(System.out::print);
//3、暴力获取所有构造方法(所有)
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
Stream.of(declaredConstructors).forEach(System.out::println);
//4、获取公有的无参构造方法
Constructor constructor1 = clazz.getConstructor(null);
//5、获取构造对象 也可以 clazz.newInstance() 直接获取
Student student = (Student)constructor1.newInstance();
//6、获取私有的有参构造方法
Constructor declaredConstructor = clazz.getDeclaredConstructor(char.class);
//7、调用私有有参构造方法(暴力访问)
declaredConstructor.setAccessible(true);
Student student1 = (Student) declaredConstructor.newInstance('男');
//三、通过反射获取属性
//1、加载Class对象
Class aClass2 = Class.forName("com.zhk.study.Student");
//2、获取公有字段
Field[] fields = aClass2.getFields();
Stream.of(fields).forEach(System.out::println);
//3、获取所有属性
Field[] declaredFields = aClass2.getDeclaredFields();
Stream.of(declaredFields).forEach(System.out::println);
//4、获取公有属性并且复制
Field name = aClass2.getField("name");
Object o = aClass2.getConstructor().newInstance();
name.set(o, "藏三");
System.out.println(((Student ) o).name);
//5、获取私有属性值
Field phoneNum = aClass2.getDeclaredField("phoneNum");
Object o1 = aClass2.getConstructor().newInstance();
phoneNum.setAccessible(true);
phoneNum.set(o1, "123");
System.out.println(((Student) o1).toString());
//四、通过反射方法
//此处省略方法同上只举一个例子
Class m = Class.forName("com.zhk.study.Student");
//公共方法
Method[] methods = m.getMethods();
//获取单个方法
m.getMethod("方法名字");
//获取有参方法
Method method = m.getMethod("方法名字", String.class);
//调用方法
Object o2 = m.getConstructor().newInstance();
method.invoke(o2, "传参");
泛型用在编译期,编译过后泛型擦除(消失掉)。所以是可以通过反射越过泛型检查的
import java.lang.reflect.Method;
import java.util.ArrayList;
/*
* 通过反射越过泛型检查
*
* 例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?
*/
public class Demo {
public static void main(String[] args) throws Exception{
ArrayList<String> strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb");
// strList.add(100);
//获取ArrayList的Class对象,反向的调用add()方法,添加数据
Class listClass = strList.getClass(); //得到 strList 对象的字节码 对象
//获取add()方法
Method m = listClass.getMethod("add", Object.class);
//调用add()方法
m.invoke(strList, 100);
//遍历集合
for(Object obj : strList){
System.out.println(obj);
}
}
}
反射暴力修改被final修饰变量可修改
shardingjdbc里面的类
//获取私有属性 TableRule.class为xxx.class actualDataNodes为xxx属性
Field actualDataNodesField = TableRule.class.getDeclaredField("actualDataNodes");
//去除final修饰符的影响,将字段设为可修改的
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(actualDataNodesField, actualDataNodesField.getModifiers() & ~Modifier.FINAL);
//可修改属性
actualDataNodesField.setAccessible(true);
//要修改它里面的actualDataNodes属性
List<DataNode> newDataNodes = new ArrayList<>();
TableRule tableRule = null;
//赋值
actualDataNodesField.set(tableRule, newDataNodes);
补充和泛型 clazz
//y 是实体 clz 传参Student.class
public <T> T test(Class<T> clz,T y) {
//带有泛型直接返回实体
T t = clz.newInstance();
return t;
}