反射
反射
1 反射
java反射机制是在运行状态中,对于任意的一个类,都能够知道这个类的所有的属性和方法,对于任意一个对象,都能够调用它的任意的属性和方法。这种动态获取信息以及动态调用对象的方法的功能称之为java语言的反射机制。
要想解剖一个类,必须先要获取这个类的字节码文件对象。
需要掌握的单词:
- Class 类
- Constructor 构造方法
- Method 方法
- Field 属性
- instance 实例对象
- invoke 执行
2 获取字节码文件对象
- 通过类名.class 获取类的字节码文件对象
- 通过对象.getClass() 获取这个对象对应的实际类的字节码文件对象
- 通过Class.forName(类的全路径名) 获取指定的类的字节码文件对象
public static void main(String[] args) throws ClassNotFoundException {
// 通过类名.class获取
Class<String> c = String.class;
System.out.println(c);
// 接口
Class<List> listClass = List.class;
System.out.println(listClass);
// 数组
Class<int[]> aClass = int[].class;
System.out.println(aClass);
// 基本数据类型
Class<Double> doubleClass = double.class;
System.out.println(doubleClass);
// 通过对象名.getClass()
Object obj = "abc";
Class<?> aClass1 = obj.getClass();
System.out.println(aClass1);
// 通过Class.forName(全路径类名)获取
Class<?> aClass2 = Class.forName("java.util.Date");
System.out.println(aClass2);
}
3 构造方法
private static void demo3()throws Exception {
// 获取字节码文件对象
Class<Person> personClass = Person.class;
// 获取任意指定的构造方法
Constructor<Person> constructor = personClass.getDeclaredConstructor(String.class,int.class,String.class);
// 暴力破解
constructor.setAccessible(true);
// 调用构造方法创建对象
Person person = constructor.newInstance("张三", 18, "郑州");
System.out.println(person);
// 获取所有公共的构造方法
Constructor<?>[] constructors = personClass.getConstructors();
for (Constructor<?> constructor1 : constructors) {
System.out.println(constructor1);
}
// 获取所有的构造方法
Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
}
4 属性
private static void demo4() throws Exception {
// 获取字节码文件对象
Class<Person> personClass = Person.class;
// 获取指定的公共的属性
// personClass.getField("");
// 获取指定的任意属性
Field name = personClass.getDeclaredField("name");
System.out.println(name);
// 暴力破解
name.setAccessible(true);
// 给属性赋值
Person person = new Person("aa",20);
System.out.println(person);
name.set(person,"张无忌");
System.out.println(person);
// 获取属性值
Object o = name.get(person);
System.out.println(o);
// 获取所有的公共属性
for (Field field : personClass.getFields()) {
System.out.println(field);
}
// 获取所有的属性
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
}
5 方法
private static void demo5() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Person person = new Person("aa",19);
// 获取字节码文件对象
Class<Person> personClass = Person.class;
// 获取公共的方法
// 参数一: 方法的名称
// 参数二: 方法的参数类型
Method method = personClass.getMethod("eat");
System.out.println(method);
// 调用方法
method.invoke(person);
// 获取非公共的方法
Method sleep = personClass.getDeclaredMethod("sleep", String.class);
System.out.println(sleep);
// 调用非公共的方法
// 暴力破解
sleep.setAccessible(true);
Object invoke = sleep.invoke(person, "时代少年团,我们喜欢你");
System.out.println(invoke);
// 获取所有的公共方法(包含继承过来的)
// for (Method personClassMethod : personClass.getMethods()) {
// System.out.println(personClassMethod);
// }
// 获取所有的方法(不包含继承的)
// for (Method declaredMethod : personClass.getDeclaredMethods()) {
// System.out.println(declaredMethod);
// }
}
6 反射的劣势
- 打破封装原则
- 跳过泛型的检查
private static void demo6() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<String> list = new ArrayList<>();
// 获取字节码文件对象
Class<? extends List> listClass = list.getClass();
// 获取add方法
Method method = listClass.getDeclaredMethod("add", Object.class);
// 执行方法
method.invoke(list,123);
System.out.println(list);
}
7 相关的获取方法
private static void demo7() throws NoSuchFieldException, NoSuchMethodException {
// 获取枚举的字节码文件对象
Class<Season> seasonClass = Season.class;
// 获取枚举常量 如果不是枚举类,返回null
Season[] enumConstants = seasonClass.getEnumConstants();
for (Season enumConstant : enumConstants) {
System.out.println(enumConstant);
}
Class<String> stringClass = String.class;
// 获取一个类实现的接口
Class<?>[] interfaces = stringClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println(anInterface);
}
// 获取父类
Class<? super String> superclass = stringClass.getSuperclass();
System.out.println(superclass);
// 获取全路径类名
String className = stringClass.getName();
System.out.println(className);
// 获取类名
String simpleName = stringClass.getSimpleName();
System.out.println(simpleName);
// 获取包
Package aPackage = stringClass.getPackage();
System.out.println(aPackage);
// 获取包名
String packageName = stringClass.getPackageName();
System.out.println(packageName);
// 获取属性的声明类型
Field field = stringClass.getDeclaredField("hash");
Class<?> type = field.getType();
System.out.println(type);
// 获取属性/方法/构造的修饰符
int modifiers = field.getModifiers();
System.out.println(modifiers);
Method method = stringClass.getDeclaredMethod("getBytes",String.class);
// 获取方法的声明类 不能获取继承的方法
System.out.println(method.getDeclaringClass());
// 获取方法的返回值类型
Class<?> returnType = method.getReturnType();
System.out.println(returnType);
// 获取方法声明的编译时异常
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
// 获取方法的参数个数
int parameterCount = method.getParameterCount();
System.out.println(parameterCount);
// 获取方法的参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println(parameterType);
}
// 获取方法的泛型
for (TypeVariable<Method> typeParameter : method.getTypeParameters()) {
System.out.println(typeParameter);
}
}

8 相关的判断方法
private static void demo8() {
// 判断是否是一个数组
System.out.println(int[].class.isArray());
// 判断是否是一个枚举
System.out.println(Season.class.isEnum());
// 判断是否是一个接口
System.out.println(List.class.isInterface());
// 判断是否是基本数据类型
System.out.println(int.class.isPrimitive());
// 判断是否是匿名内部类
Object obj = new Object(){};
System.out.println(obj.getClass().isAnonymousClass());
// 判断是否是方法内部类
System.out.println(obj.getClass().isLocalClass());
// 判断是否是成员内部类
System.out.println(obj.getClass().isMemberClass());
// 判断是否是静态内部类
System.out.println(obj.getClass().isSynthetic());
// 判断类和对象的关系
String str = "abc";
// System.out.println(str instanceof String);
System.out.println(String.class.isInstance(str));
// 判断类和类之间的关系
System.out.println(Object.class.isAssignableFrom(String.class));
// 判断接口和类之间的关系
System.out.println(Serializable.class.isAssignableFrom(String.class));
}
9 注解
9.1 自定义注解
// 数组中只有一个元素,可以省略{}
// 如果传递值时只有一个,并且属性值是value,那么可以省略 value =
@FirstAnno("abc")
public class TestDemo2 {
private int age;
public static void main(String[] args) {
int i = 10;
}
}
@interface FirstAnno{
// 注解中可以定义属性,会使用public static final修饰
// int i = 10;
// 定义属性
String value();
// double d();
// 默认值
char c() default 'a';
// 注解中的属性只能是基本数据类型/String/Class/注解/枚举以及它们所对应的一维数组的形式
// Object obj();
// int[] arr();
}
9.2 元注解
对注解进行注解的注解
@Target({ElementType.TYPE,ElementType.FIELD}) // 限定注解的使用位置
@Retention(RetentionPolicy.RUNTIME) // 限定注解的存活时期
@Documented //可以让注解生成到java的文档中
@Inherited // 会注解到类的子类上 表示注解也可以继承了
/** 类 接口 注解 枚举 Record */
TYPE,
/** 属性 */
FIELD,
/** 方法 */
METHOD,
/** 形参 */
PARAMETER,
/** 构造方法 */
CONSTRUCTOR,
/** 局部变量 */
LOCAL_VARIABLE,
/**
* 源代码
*/
SOURCE,
/**
* 编译后的class文件
*/
CLASS,
/**
* 运行时状态
*/
RUNTIME
9.3 反射注解
public class TestDemo3 {
public static void main(String[] args) throws NoSuchMethodException {
System.out.println("有一天,不小心闯了一个红灯");
// 判断Police上面有没有注解
if (Police.class.isAnnotationPresent(Level.class)){
// 获取注解的属性值
Level annotation = Police.class.getAnnotation(Level.class);
String value = annotation.value();
if ("辅警".equals(value)){
System.out.println("送50块钱");
}else if ("民警".equals(value)){
System.out.println("拘留1天");
}else if ("交警".equals(value)){
System.out.println("扣6分,罚200");
}else if ("刑警".equals(value)){
System.out.println("判刑1年");
}
}else {
System.out.println("假警察,扭送到派出所");
}
Method method = Police.class.getMethod("eat");
if (method.isAnnotationPresent(Level.class)){
String value = method.getAnnotation(Level.class).value();
if ("民警".equals(value)){
System.out.println("民警辛苦了");
}
}else {
System.out.println("呵呵呵呵呵");
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface Level{
String value();
}
@Level("刑警")
class Police{
@Level("民警")
public void eat(){
System.out.println("人都要吃饭");
}
}
课堂练习:定义方法拷贝对象,新对象的属性值和原对象相同
// 定义方法拷贝对象,新对象的属性值和原对象相同
public static Object clone(Object obj) throws InstantiationException, IllegalAccessException {
// 获取这个对象的实际类型对应的字节码文件对象
Class<?> aClass = obj.getClass();
// 利用字节码文件对象创建新的对象
Object newObj = aClass.newInstance();
// 获取这个类型中的所有的属性
Field[] declaredFields = aClass.getDeclaredFields();
// 依次获取原对象的每一个属性的值往新对象对应的属性赋值
for (Field declaredField : declaredFields) {
// 暴力破解
declaredField.setAccessible(true);
// 获取属性值
Object of = declaredField.get(obj);
// 将属性值设置到新对象上
declaredField.set(newObj,of);
}
// 返回新对象
return newObj;
}
版本二:
// 定义方法拷贝对象,新对象的属性值和原对象相同
public static Object clone(Object obj) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// 获取这个对象的实际类型对应的字节码文件对象
Class<?> aClass = obj.getClass();
// 利用字节码文件对象创建新的对象 调用的是无参构造
// Object newObj = aClass.newInstance();
// 获取构造方法 一个类中至少有一个构造方法,所以这里随便拿一个构造方法
// Student(String,int,int)
Constructor<?> declaredConstructor = aClass.getDeclaredConstructors()[0];
// 获取构造方法的参数类型
Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
// 定义一个数组,存放构造方法中属性的默认值
Object[] objs = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
// 获取每一个参数类型
Class<?> parameterType = parameterTypes[i];
// 判断参数类型是否是基本数据类型
if (parameterType.isPrimitive()){
if (parameterType == int.class || parameterType == short.class || parameterType == byte.class){
objs[i] = 0;
}else if(parameterType == long.class){
objs[i] = 0L;
}else if (parameterType == float.class){
objs[i] = 0.0F;
}else if (parameterType == double.class){
objs[i] = 0.0;
}else if (parameterType == char.class){
objs[i] = '\u0000';
}else {
objs[i] = false;
}
}else {
// 引用数据类型
objs[i] = null;
}
}
// Student(String,User,Person,int)
// new Student(null,null,null,0);
Object newObj = declaredConstructor.newInstance(objs);
// 获取这个类型中的所有的属性
Field[] declaredFields = aClass.getDeclaredFields();
// 依次获取原对象的每一个属性的值往新对象对应的属性赋值
for (Field declaredField : declaredFields) {
// 暴力破解
declaredField.setAccessible(true);
// 获取属性值
Object of = declaredField.get(obj);
// 将属性值设置到新对象上
declaredField.set(newObj,of);
}
// 返回新对象
return newObj;
}

浙公网安备 33010602011771号