一、反射机制概念
- 通过java语言中的反射机制可以操作字节码文件。
- 通过反射机制可以操作代码片段。
-
二、反射机制对应的类
java.lang.Class代决整个宁节码,代丧一个类型,代表整个类。
- java,lang.reflect.Method代表字节码中的方法字节码。代表类中的方法。
- java.lang.reflect.Constructor.代表字节码中的构造方法字书码,代表类中的构造方法
- java.lang.reflect.Field代表字节码中的属性字节码。代表类中的成员变量静态变盘十实例变量)。
三、获取Class的三种方式
返回值为字节码对象 Class类型
第一种
Class = Class.forname(“全类名”);
第二种
对象.getClass(); Class objectClass = object.getClass();
第三种
类.Class属性
四、通过反射机制相关操作
4.1 通过反射机制访问、赋值对象的属性
- 获取字节码对象,只能获取公共的属性,默认、私密都不能获取。 ```java Class userClass = Class.forName(“com.eaglslab.pojo.User”);
Field fieldName = userClass.getField(“name”);//只能获取公共的属性 Field fieldId = userClass.getField(“id”);//只能获取公共的属性
//获取属性字节码对象数组(只能获取公有的属性) Field[] fields = userClass.getFields();
2. 注意getField(“需要加入想要获取的属性”)
2. getFields()获取所有公共的属性;
2. 获取所有属性:包括私有的属性
```java
//获取属性字节码对象数组(获取所有属性)
Field[] declaredFields = userClass.getDeclaredFields();
//获取属性字节码对象数组(获取所有属性)
Field[] declaredFields = userClass.getDeclaredFields();
反射机制:通过反射机制可以给属性赋值、获取属性的修饰符、值。
//获取属性的属性名称
String fieldName = declaredField.getName();
System.out.println("属性的属性名称为 "+fieldName);
Class type = declaredField.getType();
System.out.println("属性的类型为 "+type.getSimpleName());
//获取属性的修饰符
int modifiers = declaredField.getModifiers();//返回修饰符的代号
//将修饰符的代号转换成修饰符字符串
String toString = Modifier.toString(modifiers);
4.2 通过反射机制创建实例对象
通过操作字节码创建一个实例,在学习框架时常用
//通过反射机制创建一个类的实例
Object instance = userClass.newInstance();
通过反射机制创建对象需要注意:newinstance方法需要对应的类(就是全类名对应的类)需要有无参构造否则会报错。
使用反射机制获取修改属性,属性实例对象赋值
注意流程:
获取字节码对象—>通过字节码对象创建对象—>获取属性—>(打破封装)—>给属性赋值
//创建字节码对象
Class userClass = Class.forName("com.eaglslab.pojo.User");
//通过反射机制创建一个类的实例
Object instance = userClass.newInstance();
//获取属性
Field name = userClass.getDeclaredField("name");
Field id = userClass.getDeclaredField("id");
//给属性赋值的方法注意赋值的参数(对象,值)
name.set(instance,"张三");
//打破封装 可以对私有属性进行赋值,先打破封装
id.setAccessible(true);
//给私有的属性赋值
id.set(instance,100);
- 获取方法的相关属性
由于java有重载,所有一个方法名不能指定方法,需要传入参数; 注意传入的参数需要传入参数类型 Method declaredMethod = userClass.getDeclaredMethod(“login”, String.class, String.class);
//创建字节码对象
Class userClass = User.class;
//获取方法字节码对象
//由于java有重载,所有一个方法名不能指定方法,需要传入参数;
//注意传入的参数需要传入参数类型
Method declaredMethod = userClass.getDeclaredMethod("login", String.class, String.class);
//获取方法的返回值类型
System.out.println(declaredMethod.getReturnType().getSimpleName());
//获取方法的修饰符
System.out.println(Modifier.toString(declaredMethod.getModifiers()));
System.out.println("------------------------------------------------");
//获取方法的参数
Class[] parameterTypes = declaredMethod.getParameterTypes();
for (Class parameterType : parameterTypes) {
System.out.println(parameterType.getSimpleName());
}
4.3 通过反射机制调用方法
- 通过反射调用方法 ```java //创建字节码对象 Class userClass = User.class;
//通过反射来创建实例 Object instance = userClass.newInstance();
//获取方法字节码对象 Method declaredMethod = userClass.getDeclaredMethod(“login”, String.class, String.class);
//通过反射来调用方法 Object invoke = declaredMethod.invoke(instance, “zs002”, “123456”);
System.out.println(invoke);
<a name="QOikL"></a>
##### 4.1 通过反射机制调用构造方法进行构造
10. 构造字节码对象
获取构造getDeclaredConstructor
```java
//创建字节码对象
Class userClass = User.class;
//创建实例
Object instance2 = userClass.newInstance();
//获取构造字节码对象
Constructor declaredConstructor = userClass.getDeclaredConstructor(Integer.class, String.class);
Object instance = declaredConstructor.newInstance(100, "jack");
Constructor declaredConstructor1 = userClass.getDeclaredConstructor();
Object instance1 = declaredConstructor1.newInstance();
System.out.println(instance1);
}
五、反射在以后的用途
- 反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置。
- 当我们从容器中获Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。还有在struts2的struts.xml中配置action,也是通过反射调用的action
- 通过反射机制可以解耦,降低耦合,通过操作字节码的形式创建实例。相对于new对象来说可以降低类与类之间的耦合。
- 实际开发种使用少,但是可以帮助理解各大框架的底层。
六、案例
需求:写一个工具类,将java对象属性+值拼接为一个json串。
设计流程:
- 创建字符串对象
- 创建字节码对象
- 获取全部属性保存入数组
遍历数组 循环获取属性名与属性值,进行拼接,过程中注意json格式,字符串需要添加“”。
public static String reflectToJson(Object object){
//创建StringBuilder对象,用于完成字符串的追加
StringBuilder stringBuilder = new StringBuilder();
//获取字节码对象
Class objectClass = object.getClass();
//通过反射机制来获取全部属性的信息
Field[] declaredFields = objectClass.getDeclaredFields();
stringBuilder.append("{");
//遍历属性
for (Field declaredField : declaredFields) {
//打破封装
declaredField.setAccessible(true);
//获取属性的名称
String fieldName = declaredField.getName();
//定义一个属性值
Object value = null;
try {
//获取属性值
value = declaredField.get(object);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
stringBuilder.append(fieldName+":");
//判断属性的数据类型是不是String
if (declaredField.getType().getSimpleName().equals("String")){
stringBuilder.append("\""+value+"\"");
}else {
stringBuilder.append(value);
}
stringBuilder.append(",");
}
//切割最后一个逗号
stringBuilder.deleteCharAt(stringBuilder.lastIndexOf(","));
stringBuilder.append("}");
return stringBuilder.toString();
}
七、注解
7.1 什么是注解:
是元数据(Annotation) ,是一种对代码进行说明的数据,JDK1.5引 入的新规 范,是与类、按口、枚举等<br /> 引用类型处于同个层次, 可以用在包、类、属性、方法、方法的谷数和局部变量等的前边。不影响代码的语义,可以对其进行解析。<br /><br />元注解:注解的注解;
7.2 注解的基本语法
- 在注解中可以定义属性(只能是八大数据类型+枚举数据类型),注解可以拥有属性,但不能定义方法。
在注解声明了属性后,当该注解去修饰元素时一定要给属性赋值除非有定义默认值。
赋值方式: 在使用时进行注解的赋值操作 @注解名 (name = “czf”)
默认值方式 String name()default “默认值”在注解中定义属性、只能是八大基本数据类型、String类型,枚举类型、以上类型所对应的数组
- 在定义属性时,如果属性名称时value,在给该属性赋值的时候,属性名称可以省略不写
JDK内置注解
7.3 元注解:注解的注解
注解与反射机制会配合使用。
@Target 使注解只能修饰特顶的属性 设置注解的作用域。
@Retention 设置保持性策略
-1、SOURCE设置当前注解在类加载时只 保留在源码层面,不会生产字节码对象,不可以被反射机制所获
-2、CLASS市在类加载时可以生产宇乃码文件,但是不能被反射机制获牧
-3、RUNTIME在类加花时可仪生成字节码文件,也可以被反时机制获取
@Target({ElementType.FIELD, ElementType. TYPE})
@Retention(RetentionPolicy. RUNTIME)
public @interface MyAnnotation02 {
}
7.4 注解 案例
需求:自定义一个注解,该注解可以被反射机制所获取。
如果在一个类上加上了该注解,那么该类必须包含一个行业私有id属性,如果<br /> 不包含会报错。
设计流程:主要就是通过字节码获取类中的属性、以及由Modifier获取类中获取属性修饰符。通过遍历获取的属性数组,判断是否包含有属性id,以及访问权限修饰符是否包含私有。