反射简介

反射是Java的高级特性之一,但是在实际的开发中,使用Java反射的案例却非常的少,但是反射确实在底层框架中被频繁的使用。

比如:JDBC中的加载数据库驱动程序,Spring框架中加载bean对象,以及态代理,这些都使用到反射,因为我们要想理解一些框架的底层原理,反射是我们必须要掌握的。

理解反射我们先从他的概念入手,那么什么是反射呢?

反射就是在运行状态能够动态的获取该类的属性和方法,并且能够任意的使用该类的属性和方法,这种动态获取类信息以及动态的调用对象的方法的功能就是反射。

实现上面操作的前提是能够获取到该类的字节码对象,也就是.class文件,在反射中获取class文件的方式有三种:

  1. 类名.class 如:Person.class
  2. 对象.class 如:person.class
  3. Class.forName(全类名)获取 如:Class.forName("ldc.org. demo.person")

这里有点区别的就是使用1,2(.class)方式获取Class对象,并不会初始化Class对象,而使用3(forName("全类名"))的方式会自动初始化Class对象。


反射

反射对应到Java中的类库就是在java.lang.reflect下,在该包下包含着FieldMethodConstructor类。

Field: 表示一个类的属性信息

Method: 表示类的方法信息

Constructor: 表示的是类的构造方法的信息

在反射中常用的方法,我这里做了一个列举,当然更加详细的可以查官方的API文档进行学习。

方法名 作用
getConstructors() 获取公共构造器
getDeclaredConstructors() 获取所有构造器
newInstance() 获取该类对象
getName() 获取类名包含包路径
getSimpleName() 获取类名不包含包路径
getFields() 获取类公共类型的所有属性
getDeclaredFields() 获取类的所有属性
getField(String name) 获取类公共类型的指定属性
getDeclaredField(String name) 获取类全部类型的指定属性
getMethods() 获取类公共类型的方法
getDeclaredMethods() 获取类的所有方法
getMethod(String name, Class[] parameterTypes) 获得类的特定公共类型方法
getDeclaredClasses() 获取内部类
getDeclaringClass() 获取外部类
getPackage() 获取所在包

User 类:

点击查看代码
package com.example.zhangchonghu.demo.controller.reflect;

/**
* @Description:
* @author: 张重虎
* @Date: 2022/2/17 11:20
* @Version 1.0
*/
public class User {
private String name;
public Integer age; public User() {
} public User(String name, Integer age) {
this.name = name;
this.age = age; } private void privateMethod() {
System.err.println("私有方法执行了");
} public void publicMethod(String param){
System.err.println("公有方法执行了,参数为:"+param);
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

在User的实体类中,有两个属性age和name,并且除了有两个测试方法privateMethod和publicMethod用于测试私有方法和公共方法的获取。接着执行如下代码:

点击查看代码
package com.example.zhangchonghu.demo;

import org.junit.jupiter.api.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; /**
* @Description:
* @author: 张重虎
* @Date: 2022/2/17 11:54
* @Copyright: Xi'an Dian Tong Software Co., Ltd. All Rights Reserved.
* @Version 1.0
*/
public class TestReflect {
@Test
public void test() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException, ClassNotFoundException {
//1、类名.class
/**
* Class clazz = User.class;
*/ //2、对象.class
/**
* User user = new User();
* Class clazz = user.getClass();
*/ //3、Class.forName(全类名)获取
Class clazz = Class.forName("com.example.zhangchonghu.demo.controller.reflect.User"); Constructor constructor = clazz.getConstructor(String.class, Integer.class);
//获取该类对象并设置属性的值
Object obj = constructor.newInstance("张三", 18); //获得类全类名,既包含包路径
String fullClassName = clazz.getName(); //获得类名
String className = clazz.getSimpleName(); //获取类中公共类型(public)属性
Field[] fields = clazz.getFields();
String fieldName = "";
for (Field field : fields) {
//获取属性名
fieldName = field.getName();
System.out.println("public 属性名为:" + fieldName);
} //获取类中所有的属性,包括 private 属性
Field[] fieldsAll = clazz.getDeclaredFields();
fieldName = "";
for (Field field : fieldsAll) {
fieldName = field.getName();
System.out.println("private 属性名为:" + fieldName);
} //获取指定公共属性值
Field age = clazz.getField("age");
Object value = age.get(obj);
System.err.println("公共指定属性:" + value); //获得指定的私有属性值
Field name = clazz.getDeclaredField("name");
//设置为true才能获取私有属性
name.setAccessible(true);
Object value2 = name.get(obj);
System.err.println("私有指定属性值:" + value2); //获取所有公共类型方法 这里包括 Object 类的一些方法
Method[] methods = clazz.getMethods();
String methodsName = "";
for (Method method : methods) {
methodsName = method.getName();
System.out.println("公开的方法:" + methodsName);
} //获取该类中的所有方法(包括private)
Method[] methodsAll = clazz.getDeclaredMethods();
methodsName = "";
for (Method method : methodsAll) {
methodsName = method.getName();
System.out.println("私有的方法:" + methodsName);
} //获取并使用指定方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod");//获取无参私有方法
privateMethod.setAccessible(true);
privateMethod.invoke(obj);//调用方法 Method publicMethod = clazz.getMethod("publicMethod", String.class);//获取有参数方法
publicMethod.invoke(obj, "张三");//调用有参方法
}
}

运行结果(多次运行结果顺序不相同,盲猜是和多线程有关。埋个雷,没有深入挖掘):


反射在jdk 1.5的时候允许对Class对象能够支持泛型,也称为泛化Class,具体的使用如下:

Class<User> user= User.class;
//泛化class可以直接得到具体的对象,而不再是Object
Useruser= user.newInstance();

泛化实现了在获取实例的时候直接就可以获取到具体的对象,因为在编译器的时候就会做类型检查。当然也可以使用通配符的方式,例如:Class<?>


反射优点和缺点

优点:反射可以动态的获取对象,调用对象的方法和属性,并不是写死的,比较灵活,比如你要实例化一个bean对象,你可能会使用new User()写死在代码中。

但是使用反射就可以使用class.forName(user).newInstance(),而变量名user可以写在xml配置文件中,这样就不用修改源代码,灵活、可配置。

缺点:反射的性能问题一直是被吐槽的地方,反射是一种解释操作,用于属性字段和方法的接入时要远远慢于直接使用代码,因此普通程序也很少使用反射。

spring---反射(java.lang.reflect)的更多相关文章

  1. Spring + MyBaits java.lang.reflect.InvocationTargetException 启动日志报错

    调试发现 实例化 class org.apache.ibatis.logging.slf4j.Slf4jImpl时发生异常,所以 slf4j jar 问题解决: http://www.cnblogs. ...

  2. [spring] java.lang.reflect.MalformedParameterizedTypeException

    spring中加入dubbo后报java.lang.reflect.MalformedParameterizedTypeException 因为dubbo 2.5.3 它引用的是spring 2.5. ...

  3. JAVA反射系列之Field,java.lang.reflect.Field使用获取方法

    JAVA反射系列之Field,java.lang.reflect.Field使用获取方法.   转载https://my.oschina.net/u/1407116/blog/209383 摘要 ja ...

  4. JAVA中反射机制五(java.lang.reflect包)

    一.简介 java.lang.reflect包提供了用于获取类和对象的反射信息的类和接口.反射API允许对程序访问有关加载类的字段,方法和构造函数的信息进行编程访问.它允许在安全限制内使用反射的字段, ...

  5. java反射(java.lang.reflect) ---普通单例模式唯一性问题

    1. 普通的饱汉式.饿汉式 package org.bighead.test2; public class TestPrivate { private String str = "strPr ...

  6. Java反射API研究(2)——java.lang.reflect详细内容与关系

    对于最新的java1.8而言,reflect中接口的结构是这样的: java.lang.reflect.AnnotatedElement java.lang.reflect.AnnotatedType ...

  7. JAVA中反射机制六(java.lang.reflect包)

    一.简介 java.lang.reflect包提供了用于获取类和对象的反射信息的类和接口.反射API允许对程序访问有关加载类的字段,方法和构造函数的信息进行编程访问.它允许在安全限制内使用反射的字段, ...

  8. springmvc错误集锦-dubbo包含低版本的spring包,依赖的时候应该排除Caused by: java.lang.reflect.MalformedParameterizedTypeException

    dubbo 常见错误 1. Caused by: java.lang.reflect.MalformedParameterizedTypeException 启动时报错,原因是dubbo 依赖 spr ...

  9. java反射(java.lang.reflect)---java.lang.reflect.Modifier中状态码

    1. 详情请看jvm(虚拟机)规范 java.lang.reflect.Modifier public static final int ABSTRACT 1024 public static fin ...

  10. java.lang.reflect.Method.getAnnotation()方法示例【通过反射获取到方法对象再获取方法对象上的注解信息】

    转: java.lang.reflect.Method.getAnnotation()方法示例 java.lang.reflect.Method.getAnnotation(Class <T&g ...

随机推荐

  1. PlayWright(二十一)- Pytest插件报告

    1.下载 pytest框架有官方的报告pip install pytest-html   下载成功,那我们怎么使用呢?   2.使用 可以直接在配置文件里使用   在 pytest 配置文件中, 增加 ...

  2. docker部署zabbix 6.0高可用集群实验

    0 实验环境 虚拟机,postgresql本地部署,zabbix server及nginx容器部署 1 postgresql 参看前作 <postgresql + timescaledb离线安装 ...

  3. 公网环境部署zabbix5.0

    实验环境 虚拟机两台,一台公网地址为 1.1.1.1,部署 zabbix server,一台公网地址为 1.1.1.2,部署 zabbix proxy,系统为centos7.2. 1 zabbix s ...

  4. 代码随想录算法训练营第一天| LeetCode 704. 二分查找、LeetCode 27. 移除元素

    704. 二分查找         题目链接:https://leetcode.cn/problems/binary-search/       视频链接:https://www.bilibili.c ...

  5. 借助 mkcert 和批处理命令生成局域网证书

    借助 mkcert 和批处理命令生成局域网证书 自动获取ipv4,一键生成很方便 cd /d %~dp0 ipconfig |find "IPv4" > ipv4 set / ...

  6. vite — 超快且方便的编译工具

    我们编写的代码,比如 ES6. TypeScript.react 等是不能被浏览器直接识别的,需要通过 webpack .rollup 这样的构建工具来对代码进行转换.编译. 但随着项目越来越大,需要 ...

  7. MySql之锁

    MySql之锁 一.全局锁 对整个数据库加锁 应用:数据库所有表备份 二.表级锁 1.表锁 分为两类: 表共享读锁read lock 表独占写锁write lock 2.元数据锁 避免DML语句和DD ...

  8. 解决Avalonia 11.X版本的中文字体问题

    网上搜索的方法使用接口"IFontManagerImpl"这个方法目前只能用于Avalonia 10.X版本,因为11版本后官方把这个接口的成员都设置成了非plubic,所以之前的 ...

  9. SimpleDateFormat 线程安全问题修复方案

    问题介绍 在日常的开发过程中,我们不可避免地会使用到 JDK8 之前的 Date 类,在格式化日期或解析日期时就需要用到 SimpleDateFormat 类,但由于该类并不是线程安全的,所以我们常发 ...

  10. 「BJWC2012」冻结题解

    「BJWC2012」冻结题解 一.题目 "我要成为魔法少女!" "那么,以灵魂为代价,你希望得到什么?" "我要将有关魔法和奇迹的一切,封印于卡片之中 ...