只知道java反射,宁知道内省吗?
1. 前言
在上一文中我们封装了一个Mybatis通用 Mapper。为了获得实体类属性我使用了反射。大多数同学也第一感觉会用反射实现,其实还有一种技术也能实现,这就是内省(Introspector)。
2. 什么是内省
在计算机科学中,内省是指计算机程序在运行时(Runtime)检查对象(Object)类型的一种能力,通常也可以称作运行时类型检查。不应该将内省和反射混淆。相对于内省,反射更进一步,是指计算机程序在运行时(Runtime)可以访问、检测和修改它本身状态或行为的一种能力。
Java中的内省是对JavaBean属性、的一种缺省处理方法。看了概念是不是有点懵逼,我也一样。所以我们写个例子来看看就知道了。写之前还要搞清楚JavaBean的定义;
- 属性是私有的。
- 有无参的public构造方法。
- 对于这些属性有公开的getter/setter方法。
但是如果有的类比较“调皮” ,有getter/setter没有对应的实体,也容易被内省到,但是会抛出异常。所以遵守规约是一个有利于我们使用内省。
其实 add/remove、is 也认为是操作JavaBean属性的方法,所以我们要小心。
3. Java 内省操作
JavaBean一般用来传递数据使用,我们数据库实体类就是一种典型的JavaBean。
public class UserInfo implements Serializable {
private static final long serialVersionUID = -8938650956516110149L;
private Long userId;
private String name;
private Integer age;
private String time;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
请注意我特意没有给time
属性设置getter/setter
。接下来我就开始演示使用内省来操作实体了。
Java中通过java.beans.Introspector
来进行内省操作。常用的内省操作主要有下面这些,当然还有其它的附加类型。
Java 内省
3.1 BeanInfo
BeanInfo
就是内省对 JavaBean 的一个整体描述。这里我只想获取UserInfo
的描述信息,所以应该这么写:
BeanInfo beanInfo = Introspector.getBeanInfo(UserInfo.class,Object.class);
你可以通过 stop 、flag 两个属性来控制内省分析的深度。
3.2 BeanDescriptor
然后我们看看BeanDescriptor
主要有什么:
BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();
// cn.felord.kono.entity.UserInfo.class
Class<?> beanClass = beanDescriptor.getBeanClass();
// UserInfo
String name = beanDescriptor.getName();
原来是JavaBean的Class
类型和名称。
3.3 PropertyDescriptors
PropertyDescriptor
是描述JavaBean的成员属性的,我们打印来看看
Stream.of(beanInfo.getPropertyDescriptors())
.forEach(System.out::println);
java.beans.PropertyDescriptor[name=age; propertyType=class java.lang.Integer; readMethod=public java.lang.Integer cn.felord.kono.entity.UserInfo.getAge(); writeMethod=public void cn.felord.kono.entity.UserInfo.setAge(java.lang.Integer)]
java.beans.PropertyDescriptor[name=name; propertyType=class java.lang.String; readMethod=public java.lang.String cn.felord.kono.entity.UserInfo.getName(); writeMethod=public void cn.felord.kono.entity.UserInfo.setName(java.lang.String)]
java.beans.PropertyDescriptor[name=userId; propertyType=class java.lang.Long; readMethod=public java.lang.Long cn.felord.kono.entity.UserInfo.getUserId(); writeMethod=public void cn.felord.kono.entity.UserInfo.setUserId(java.lang.Long)]
原来PropertyDescriptor
包含了成员属性的名称、类型、读的方法、写的方法。注意到没有居然不包含time
属性,因为它没有getter/setter被忽略了。
3.4 MethodDescriptors
顾名思义,一定是描述JavaBean的方法的。这里放出一条打印结果。
java.beans.MethodDescriptor[name=foo; method=public static void cn.felord.kono.entity.UserInfo.foo(java.lang.String)]
包含了方法名称和方法对象(Method
)。注意这里混进来了奇怪的方法 foo
,是的!我随便写了一个方法。MethodDescriptors 可以包含JavaBean下所有的方法,包括静态方法。当然受到内省深度的制约。
3.5 EventSetDescriptors
目前打印为空,JavaBean 事件发布订阅相关的一些范式,目前我还不知道什么作用。
4. 总结
Java反射是在运行时获取一个类的所有信息,可以操纵类的字段、方法、构造器等,功能非常强大。而内省其实就是反射的一个子集,基于反射实现。专门操作JavaBean的,只关注于JavaBean的属性、方法、事件的一些属性。了解了这个我觉得有必要把通用Mapper重构一下了。
- Docker Hub工作流程-Docker for Web Developers(6)
- PHP+MySQL代码部署在Linux(Ubuntu)上注意事项
- mac系统上使用压缩包版的mysql(非安装版)
- oracle的decode函数在mysql的实现
- Python的解码和编码
- 原生Ajax总结
- 多个知名化妆品牌现假官网,域名保护该受重视
- JavaScript操作Cookie
- Windows下Go环境安装
- Angular定义服务-Learn By Doing
- JS魔法堂:不完全国际化&本地化手册 之 理論篇
- mysql替换某个字段中的某个字符
- Angular企业级开发(1)-AngularJS简介
- PHP在Apache下500错误
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Linux硬盘合并的实现代码
- 虚拟机Linux桥接模式下设置静态IP详解
- Linux平台安装redis及redis扩展的方法
- Linux环境下快速搭建ftp服务器方法介绍
- Linux通过匿名管道进行进程间通信
- shell判断一个变量是否为空方法总结
- 基于ubuntu16 Python3 tensorflow(TensorFlow环境搭建)
- Linux中的iostat命令使用教程
- 深入解读Linux进程函数fork(),vfork(),execX()
- Linux centos下设置定时备份任务的方法步骤
- Linux 中如何切换相同程序的不同版本
- Linux中查看指定文件夹内各个子文件夹内的文件数量
- Linux系统中 /etc/fstab 文件的深入解读
- bash命令使用详解
- 实例详解Linux 中的命令链接操作符