反射在java中使用频率还是比较高的,比如JDK动态代理使用反射获取到目标类所有的接口列表。还有我们熟悉的JDBC获取驱动,Class.forName(“com.mysql.jdbc.Driver”)
定义
在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。
术语
RTTI(Run-Time Type Identification),通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。
反射和非反射的差异
反射是在运行期间动态获取class文件进行读取其中的信息,而普通的RTTI(非反射)就是在编译器获取class文件信息并加入到类加载器中
获取类的加载时机的区别:
生成对象步骤的区别:
反射的基本使用
比如修改private final的属性值
// 必须通过反射调用,获取PrismSettings类的disableEffects字段
Field field = PrismSettings.class.getDeclaredField("disableEffects");
// 获取修饰符字段对象
Field modifiersField = Field.class.getDeclaredField("modifiers");
// 设置可修改为true
modifiersField.setAccessible(true);
// 作用到disableEffects字段上,并修改原本final的修饰符为非final
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, true);
获取UserService对象中的userDao私有字段
// 获取字段
Field field = UserService.class.getDeclaredField("userDao");
// 设置为可修改
field.setAccessible(true);
// 获取字段对象
UserDao userDao = (UserDao) field.get(userService);
使用反射实现自定义注解
创建一个可以注解在方法上的注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMethodAnnotation {
String value() default "";
}
创建一个对象User使用方法注解并在visit()方法上添加注解@MyMethodAnnotation
public class User {
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
@MyMethodAnnotation(value = "我是value")
public void visit(){
}
}
通过扫描package,获取每个类下的方法并判断是否有注解
@Test
public void test() throws ClassNotFoundException {
// 获取此包下所有的类全限定名
List<String> classNameList = ReflectUtils.doScanner("com.siqi.java.reflect");
for (String className : classNameList) {
Class<?> clazz = Class.forName(className);
// 获取所有的方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(MyMethodAnnotation.class)) {
// 获取方法上指定的注解
MyMethodAnnotation myMethodAnnotation = method.getAnnotation(MyMethodAnnotation.class);
System.out.println("方法上有@MyMethodAnnotation注解 = " + method.getName() +
// 获取注解中的value
" value = " + myMethodAnnotation.value());
}
}
}
}
反射工具类,拥有扫描package的方法
public class ReflectUtils {
/**
* 获取所有要扫描的包的全限定名
*
* @param packageName
*/
public static List<String> doScanner(String packageName) {
List<String> classNameList = new ArrayList<>();
//把所有的.替换成/
URL url = ReflectUtils.class.getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
File dir = new File(url.getFile());
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
//递归读取包
doScanner(packageName + "." + file.getName());
} else {
String className = packageName + "." + file.getName().replace(".class", "");
classNameList.add(className);
}
}
return classNameList;
}
}
总结
除了自定义注解,我们还可以采用反射机制实现一个BeanUtils,可以将一个对象的相同属性赋值给另一个对象,实现对象的clone功能
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/17883.html