# 反射
## 概述
java反射机制是在程序**运行状态**
中,对于任意一个类,都能够知道这个类的所有的属性和方法。对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取的信息以及动态调用对象的方法的功能称之为java的反射机制。
要想解剖一个类,必须先要获取这个类的字节码文件对象。解剖这个类,使用的就是Class类中的方法。字节码文件对象就对应到Class类型的对象
要掌握的单词:
– Class 类
– Constructor 构造方法
– Method 方法
– Field 属性
– Instance 实例
– invoke 执行
## 获取Class对象
“
通过类字面量:
“`
Class> clazz = String.class;
“`
通过对象实例:
“`
String str = “Hello”;
Class> clazz = str.getClass();
“`
通过 Class.forName() 方法:
“`
Class> clazz = Class.forName(“java.lang.String”);
“`
## 创建对象
可以使用反射动态创建对象:
“`
Class> clazz = Class.forName(“java.lang.String”);
Object obj = clazz.getDeclaredConstructor().newInstance();
“`
“`java
import java.util.ArrayList;
import java.util.List;
public class AddUserTest {
public static void main(String[] args) throws ClassNotFoundException {
//获取Class对象
//方式一
//接口名/类名.class
Class
System.out.println(stringClass);
Class lsitclass = List.class;
System.out.println(lsitclass);
Class
System.out.println(aclass);
Class
System.out.println(integerClass);
Class
System.out.println(doubleClass);
//对象名.getClass();
//方式二
List
System.out.println(list.getClass());
//方式三
//字符串必须是全路径名
Class> aClass1 = Class.forName(“java.util.Date”);
System.out.println(aClass1);
Class> aClass2 = Class.forName(“cn.javasm.Testdemo”);
System.out.println(aClass2);
}
}
“`
## 访问字段
可以通过反射访问和修改类的字段:
“`
Class> clazz = Person.class;
Field field = clazz.getDeclaredField(“name”);
// 如果字段是私有的,需要设置为可访问
field.setAccessible(true);
// 获取字段值
Object value = field.get(personInstance);
// 设置字段值
field.set(personInstance, “New Name”);
“`
“`java
import java.lang.reflect.Field;
public class TestDemo3 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
// 获取字符串的hash属性
// 获取字节码文件对象
Class
// 获取serialVersionUID属性
// stringClass.getDeclaredField(“serialVersionUID”);
// stringClass.getDeclaredFields();
Field field = stringClass.getDeclaredField(“hash”);
System.out.println(field);
//暴力破解
String str = “abc”;
field.setAccessible(true);
field.set(“str”, 10);
Object obj = field.get(str);
System.out.println(obj);
//获取所有的属性
Field[] declaredFields = stringClass.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f);
}
//获取属性的修饰符
int modifiers = field.getModifiers();
System.out.println(modifiers);
Class
Field name = personClass.getDeclaredField("name");
System.out.println(name);
System.out.println(name.getModifiers());
}
}
“`
### 修饰符对应返回值
;
method.invoke(personInstance);
Method methodWithArgs = clazz.getMethod(“greet”, String.class);
methodWithArgs.invoke(personInstance, “World”);
“`
获取公共方法 & 获取非公开的方法
“`java
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestDemo4 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// method1();
// method2();
}
private static void method2() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
//获取字节码文件对象
Class
//获取公共方法
Method method = staringClass.getMethod(“substring”, int.class, int.class);
String str = “abcd”;
// 执行方法
// 参数一 要执行的对象
// 参数二 方法的实参
// 返回值就是方法的返回值
Object invoke = method.invoke(str, 1, 3);
System.out.println(invoke);
}
private static void method1() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
//获取字节码文件对象
Class
//获取非公开的方法
Method method = personClass.getDeclaredMethod(“eat”);
Person person = new Person(“cyz”, 22);
//暴力破解
method.setAccessible(true);
//执行方法
Object invoke = method.invoke(person);
System.out.println(invoke);
}
}
“`
获取枚举类
“`java
public class TestDemo5 {
public static void main(String[] args) {
// 获取字节码文件对象
Class
// 获取枚举Level中的所有的枚举常量
Level[] enumConstants = levelClass.getEnumConstants();
for (Level enumConstant : enumConstants) {
System.out.println(enumConstant);
}
}
enum Level {
A, B, C, D, E
}
}
“`
如果不是枚举 返回null
“`java
public static void method2() {
Class
String[] enumConstants1 = stringClass.getEnumConstants();
System.out.println(enumConstants1);
}
“`
## 获取接口和父类
可以使用反射获取类实现的接口和父类:
“`
Class> clazz = Person.class;
// 获取所有接口
Class>[] interfaces = clazz.getInterfaces();
for (Class> i : interfaces) {
System.out.println(“Interface: ” + i.getName());
}
// 获取父类
Class> superClass = clazz.getSuperclass();
System.out.println(“Superclass: ” + superClass.getName());
“`
获取所有接口
“`java
public class TestDemo6 {
public static void main(String[] args) {
Class
Class>[] interfaces = stringClass.getInterfaces();
for (Class> i : interfaces) {
System.out.println(i);
}
}
}
“`
// 获取父类 全路径类名 类名 包名
“`java
public class TestDemo6 {
public static void main(String[] args) {
Class
//获取父类
Class super String> superclass = stringClass.getSuperclass();
System.out.println(superclass);
//获取全路径类名
String name = superclass.getName();
System.out.println(name);
//获取简单类名
String simpleName = superclass.getSimpleName();
System.out.println(simpleName);
//获取包名
System.out.println(stringClass.getPackageName());
}
}
“`
## 获取构造方法
可以使用反射获取和调用构造函数:
“`
Class> clazz = Person.class;
Constructor> constructor = clazz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance(“John”, 30);
“`
“`java
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class TestDemo2 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取字符串字节码文件对象
Class
// 获取构造方法
//public String(byte ascii[], int hibyte, int offset, int count)
Constructor
// 创建对象
String string = constructor.newInstance(new byte[]{97, 98, 99}, 0, 3);
System.out.println(string);
//获取所有公共的构造方法
Constructor>[] constructors = stringClass.getConstructors();
for (Constructor> constructor1 : constructors) {
System.out.println(constructor1);
}
//获取指定的构造方法
Constructor
System.out.println(declaredConstructor);
//暴力破解
declaredConstructor.setAccessible(true);
String s1 = declaredConstructor.newInstance(new byte[]{97, 98, 99});
System.out.println(s1);
//获取所有构造方法
Constructor>[] declaredConstructors = stringClass.getDeclaredConstructors();
for (Constructor> declaredConstructor1 : declaredConstructors) {
System.out.println(declaredConstructors);
}
}
}
“`
## 反射劣势
1 反射打破了封装原则
2 可以跳过泛型检查
“`java
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List
// 获取字节码文件对象
Class extends List> aClass = list.getClass();
// 获取add方法
Method method = aClass.getMethod(“add”, Object.class);
// 执行方法
method.invoke(list, 12);
System.out.println(list);
}
“`
## Method和Field相关方法
## 判断方法
“`java
@FirstAnno(“abc”)
public class TestDemo10 {
int j = 20;
public static void main(String[] args) {
int i = 10;
}
}
// 自定义注解
@interface FirstAnno {
// 在注解中可以定义属性,默认被public static final修饰
public static final int i = 10;
// 在注解中定义变量 使用()
// 注解中的属性使用public修饰
// String str();
//
// double d();
// 设置默认值
char c() default ‘国’;
// 注解中的属性类型只能是基本数据类型/String/Class/注解/枚举以及它们的一维数组形式
// Object obj();
// 如果数组中只有一个元素, {} 可以省略
// int[] arr();
// 如果传递值时只有一个值,并且名称是value,那么可以省略value =
String value();
}
“`
## 注解
### 自定义注解
“`java
@FirstAnno(“abc”)
public class TestDemo10 {
int j = 20;
public static void main(String[] args) {
int i = 10;
}
}
// 自定义注解
@interface FirstAnno {
// 在注解中可以定义属性,默认被public static final修饰
public static final int i = 10;
// 在注解中定义变量 使用()
// 注解中的属性使用public修饰
// String str();
//
// double d();
// 设置默认值
char c() default ‘国’;
// 注解中的属性类型只能是基本数据类型/String/Class/注解/枚举以及它们的一维数组形式
// Object obj();
// 如果数组中只有一个元素, {} 可以省略
// int[] arr();
// 如果传递值时只有一个值,并且名称是value,那么可以省略value =
String value();
}
“`
### 元注解
对注解进行注解的那些注解
“`java
@Target({ElementType.METHOD, ElementType.TYPE}) // 限定注解的使用范围
@Retention(RetentionPolicy.RUNTIME) //限定注解的存活范围
@Inherited // 表示这个注解也要作用在子类上
@Documented // 表示这个注解会生成到java文档中
“`
### 10.3 反射注解
“`java
public class TestDemo11 {
public static void main(String[] args) throws NoSuchMethodException {
// 获取字节码文件对象
Class
Method method = teacherClass.getMethod(“teach”);
// 判断类或者方法或者属性上面是否有指定的注解isAnnotationPresent
if (teacherClass.isAnnotationPresent(Anno.class)) {
// 获取所有注解
// teacherClass.getAnnotations();
Anno annotation = teacherClass.getAnnotation(Anno.class);
// 获取注解的值
String value = annotation.value();
if (“初级”.equals(value)) {
System.out.println(“认真负责”);
} else if (“中级”.equals(value)) {
System.out.println(“三尺讲台,两袖清风”);
} else if (“特级”.equals(value)) {
System.out.println(“桃李满天下”);
} else {
System.out.println(“辅导员…”);
}
} else {
System.out.println(“野鸡老师……”);
}
}
}
@Anno(“特级”)
class Teacher {
public void teach() {
System.out.println(“老师要教书育人”);
}
}
@Retention(RetentionPolicy.RUNTIME)// 保留到运行阶段
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Anno {
String value();
}
“`