大多数人不知道的Java知识 - Java内省机制

Java内省(Introspector)是Java语言对Bean类属性、方法,事件的一种缺省处理方法。例如类Person中有属性name,那我们可以通过getName,setName来得到其值或者设置新的值。通过getName/setName来访问name属性,这就是默认的规则。Java中提供了一套API用来访问某个属性的getter/setter方法,通过这些API可以使你不需要了解这个规则(但你最好还是要搞清楚),这些API存放于包java.beans中。

一般的做法是通过类Introspector来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器PropertyDescriptor,通过这个属性描述器就可以获取某个属性对应的getter/setter方法,最后就可以通过反射机制来调用这些方法了。

Introspector

=======================================================================

官方介绍

The Introspector class provides a standard way for tools to learn about the properties, events, and methods supported by a target Java Bean.

For each of those three kinds of information, the Introspector will separately analyze the bean’s class and superclasses looking for either explicit or implicit information and use that information to build a BeanInfo object that comprehensively describes the target bean.

java.beans.Introspector,即内省。它提供了一套标准的访问Java Bean的属性事件以及方法的处理方法。 对于Java Bean的这3种信息,Introspector会分析Java Bean以及它的父类的显示和隐式的信息,然后构建一个全面描述此Java Bean的BeanInfo对象。

在Java中,JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的属性,且方法名符合某种命名规则。例如DTO,VO等,我们在业务或者模块之间传递信息,可以将信息封装到JavaBean中。

既然封装到JavaBean中,那就会有设置(setter)和读取(getter)JavaBean中私有属性等操作。Introspector可以帮我们做到这件事,不过要注意,JavaBean中的getter和setter等方法要遵循某种规范。(驼峰规则)

package com.nobody;

/**

  • @Description JavaBean类

  • @Author Mr.nobody

  • @Date 2021/1/24

  • @Version 1.0

*/

public class Person {

private String id;

private String name;

private int age;

public Person(String id, String name, int age) {

this.id = id;

this.name = name;

this.age = age;

}

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

package com.nobody;

import java.beans.*;

/**

  • @Description

  • @Author Mr.nobody

  • @Date 2021/3/23

  • @Version 1.0.0

*/

public class Demo {

public static void main(String[] args) throws IntrospectionException {

// 不内省父类的信息,第二个参数stopClass代表从stopClass开始往上的父类不再内省

BeanInfo beanInfo = Introspector.getBeanInfo(Person.class, Object.class);

// 会内省起所有父类的信息

BeanInfo includeParentBeanInfo = Introspector.getBeanInfo(Person.class);

}

}

BeanInfo

===================================================================

官方介绍

Use the BeanInfo interface to create a BeanInfo class and provide explicit information about the methods, properties, events, and other features of your beans.

java.beans.BeanInfo是一个接口,它有几个默认的实现类,我们一般默认生成的BeanInfo对象其实是GenericBeanInfo类的实例。简而言之,BeanInfo对象能提供关于JavaBean的方法,属性,事件以及其他特征的明确信息。 其主要方法如下:

  • getPropertyDescriptors():获得所有属性描述器。

  • getBeanDescriptor():获得对象描述器。

  • getMethodDescriptors():获得所有方法描述器。

  • getEventSetDescriptors():获得所有事件描述器。

package com.nobody;

import java.beans.*;

/**

  • @Description

  • @Author Mr.nobody

  • @Date 2021/3/23

  • @Version 1.0.0

*/

public class Demo {

public static void main(String[] args) throws IntrospectionException {

// 不内省父类的信息,第二个参数stopClass代表从stopClass开始往上的父类不再内省

BeanInfo beanInfo = Introspector.getBeanInfo(Person.class, Object.class);

BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();

PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();

EventSetDescriptor[] eventSetDescriptors = beanInfo.getEventSetDescriptors();

}

}

BeanDescriptor

=========================================================================

官方介绍

A BeanDescriptor provides global information about a “bean”, including its Java class, its displayName, etc.

This is one of the kinds of descriptor returned by a BeanInfo object, which also returns descriptors for properties, method, and events.

java.beans.BeanDescriptor,即对象描述器。它提供了一个JavaBean的全局信息,例如JavaBean的类型,类名等信息。

我们一般是从BeanInfo对象获取BeanDescriptor对象,不过也可以直接通过new BeanDescriptor(Class<?> beanClass)构造函数获取。

package com.nobody;

import java.beans.*;

/**

  • @Description

  • @Author Mr.nobody

  • @Date 2021/3/23

  • @Version 1.0.0

*/

public class Demo {

public static void main(String[] args) throws IntrospectionException {

// 不内省父类的信息,第二个参数stopClass代表从stopClass开始往上的父类不再内省

BeanInfo beanInfo = Introspector.getBeanInfo(Person.class, Object.class);

// 从BeanInfo对象获取BeanDescriptor对象

BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor();

// 通过new BeanDescriptor(Class<?> beanClass)构造函数获取BeanDescriptor对象

// BeanDescriptor beanDescriptor = new BeanDescriptor(Person.class);

Class<?> beanClass = beanDescriptor.getBeanClass();

Class<?> customizerClass = beanDescriptor.getCustomizerClass();

String displayName = beanDescriptor.getDisplayName();

String name = beanDescriptor.getName();

System.out.println(“beanClass:” + beanClass);

System.out.println(“customizerClass:” + customizerClass);

System.out.println(“displayName:” + displayName);

System.out.println(“name:” + name);

PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();

EventSetDescriptor[] eventSetDescriptors = beanInfo.getEventSetDescriptors();

}

}

输出结果如下:

beanClass:class com.nobody.Person

customizerClass:null

displayName:Person

name:Person

PropertyDescriptor

=============================================================================

官方介绍

A PropertyDescriptor describes one property that a Java Bean exports via a pair of accessor methods.

java.beans.PropertyDescriptor,即属性描述器。描述了Java Bean的一个属性,通过一对读取方法。即PropertyDescriptor里面封装了JavaBean的其中一个属性的相关信息(例如属性名,属性类型,get和set等方法)。其主要方法如下:

  • getName():获得属性名。

  • getPropertyType():获得属性类型。

  • getReadMethod():获得用于读取属性值的方法。

  • getWriteMethod():获得用于写入属性值的方法。

  • setReadMethod(Method readMethod):设置用于读取属性值的方法。

  • setWriteMethod(Method writeMethod):设置用于写入属性值的方法。

package com.nobody;

import java.beans.*;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.util.UUID;

/**

  • @Description

  • @Author Mr.nobody

  • @Date 2021/3/23

  • @Version 1.0.0

*/

public class Demo {

public static void main(String[] args)

throws IntrospectionException, InvocationTargetException, IllegalAccessException {

// 不内省父类的信息,第二个参数stopClass代表从stopClass开始往上的父类不再内省

BeanInfo beanInfo = Introspector.getBeanInfo(Person.class, Object.class);

Person person = new Person(UUID.randomUUID().toString(), “Mr_nobody”, 18);

PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {

Class<?> propertyType = propertyDescriptor.getPropertyType();

String propertyName = propertyDescriptor.getName();

Method readMethod = propertyDescriptor.getReadMethod();

Method writeMethod = propertyDescriptor.getWriteMethod();

System.out.println(“属性名:” + propertyName);

System.out.println(“属性类型:” + propertyType);

System.out.println(“写方法名:” + writeMethod.getName());

System.out.println(“读方法名:” + readMethod.getName());

if (“age”.equals(propertyName)) {

writeMethod.invoke(person, 20);

}

System.out.println(“属性值:” + readMethod.invoke(person));

System.out.println(“------------------------------------------”);

}

}

}

输出结果:

属性名:age

属性类型:int

写方法名:setAge

读方法名:getAge

属性值:20


属性名:id

属性类型:class java.lang.String

写方法名:setId

读方法名:getId

属性值:a6ccda55-c895-438e-893f-7fa448aba35a


属性名:name

属性类型:class java.lang.String

写方法名:setName

读方法名:getName

属性值:Mr_nobody


当然,除了从BeanInfo对象获取PropertyDescriptor对象,也可以直接new的方式获取。

PropertyDescriptor namePropertyDescriptor = new PropertyDescriptor(“name”, Person.class);

MethodDescriptor

===========================================================================

java.beans.MethodDescriptor,即方法描述器,通过它可以获取到类相关的方法,如下所示:

package com.nobody;

import java.beans.*;

import java.lang.reflect.Method;

import java.lang.reflect.Type;

/**

  • @Description

  • @Author Mr.nobody

  • @Date 2021/3/23

  • @Version 1.0.0

*/

public class Demo {

public static void main(String[] args) throws IntrospectionException {

// 不内省父类的信息,第二个参数stopClass代表从stopClass开始往上的父类不再内省

BeanInfo beanInfo = Introspector.getBeanInfo(Person.class, Object.class);

MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();

for (MethodDescriptor methodDescriptor : methodDescriptors) {

Method method = methodDescriptor.getMethod();

System.out.println(method);

System.out.println(“方法名:” + method.getName());

Type[] genericParameterTypes = method.getGenericParameterTypes();

if (genericParameterTypes != null) {

for (Type genericParameterType : genericParameterTypes) {

System.out.println(“方法参数类型:” + genericParameterType.getTypeName());

}

}

Class<?> returnType = method.getReturnType();

System.out.println(“方法返回类型:” + returnType.getTypeName());

System.out.println(“---------------------------”);

}

}

}

输出结果如下:

public java.lang.String com.nobody.Person.getName()

方法名:getName

方法返回类型:java.lang.String


public void com.nobody.Person.setId(java.lang.String)

方法名:setId

方法参数类型:java.lang.String

方法返回类型:void


public void com.nobody.Person.setAge(int)

方法名:setAge

方法参数类型:int

方法返回类型:void


public void com.nobody.Person.setName(java.lang.String)

方法名:setName

方法参数类型:java.lang.String

方法返回类型:void


public int com.nobody.Person.getAge()

方法名:getAge

方法返回类型:int


public java.lang.String com.nobody.Person.getId()

方法名:getId

方法返回类型:java.lang.String


public java.lang.String com.nobody.Person.toString()

方法名:toString

方法返回类型:java.lang.String


内省应用

===============================================================

在项目实战中,我们一般使用最多的是 IntrospectorBeanInfoPropertyDescriptor,这三者结合起来使用。

比如,我们通过内省可以实现,JavaBean和Map互转,不同JavaBean对象属性拷贝等功能。

package com.nobody.util;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后总结

ActiveMQ+Kafka+RabbitMQ学习笔记PDF

image.png

  • RabbitMQ实战指南

image.png

  • 手写RocketMQ笔记

image.png

  • 手写“Kafka笔记”

image

关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后总结

ActiveMQ+Kafka+RabbitMQ学习笔记PDF

[外链图片转存中…(img-RLk6O6rW-1713627606373)]

  • RabbitMQ实战指南

[外链图片转存中…(img-OMFnxm9m-1713627606375)]

  • 手写RocketMQ笔记

[外链图片转存中…(img-6bs4fYdA-1713627606375)]

  • 手写“Kafka笔记”

[外链图片转存中…(img-8OxGLxDd-1713627606375)]

关于分布式,限流+缓存+缓存,这三大技术(包含:ZooKeeper+Nginx+MongoDB+memcached+Redis+ActiveMQ+Kafka+RabbitMQ)等等。这些相关的面试也好,还有手写以及学习的笔记PDF,都是啃透分布式技术必不可少的宝藏。以上的每一个专题每一个小分类都有相关的介绍,并且小编也已经将其整理成PDF啦
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 27
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值