Java 基础知识之 JavaBean

简介: 什么是 内省(Introspector) ?Java 内省(Introspector)提供了根据 Java 类元信息获取 JavaBean 信息的接口,底层使用了反射实现。

什么是 内省(Introspector) ?

Java 内省(Introspector)提供了根据 Java 类元信息获取 JavaBean 信息的接口,底层使用了反射实现。


什么是 JavaBean ?

JavaBean 是方法名具备某些命名规范的Java 类,封装了属性,方法和事件, 在 Java 中使用接口 BeanInfo 表示,通过该接口可以轻松获取到 JavaBean 的信息。


通过对 Introspector 源码的阅读可以了解到 JavaBean 方法命名的规范如下。


JavaBean 属性:

JavaBean 的属性使用 Java 类 PropertyDescriptor 描述,一个 JavaBean包含多个 PropertyDescriptor 。 PropertyDescriptor 主要包含属性的类型、读方法、写方法,属性信息根据方法获取,并不要求一定存在和 set/get 方法对应的成员变量,不要求读方法和写方法同时存在。


属性类型:为读方法的返回值类型,写方法参数类型需要和读方法返回值类型一致或者为读方法返回值类型的子类。

JavaBean 属性方法规范

读方法(readMethod)

返回值类型:不能为 void 。

方法名:一般以get开头,返回值类型为 boolean 时以 is开头,只包含一个类型为 int 的参数时必须以 get 开头。

参数:参数一般为空,或包含一个 int 类型的参数用于表示索引位置。

写方法(writeMethod)

返回值类型:必须为void 。

方法名:必须以 set开头 。

参数:可以有1个或者2个参数,有两个参数时第一个参数类型为 int 。

如何使用 Introspector 获取 PropertyDescriptor

创建父类 Person

package com.zuhkp.java.basic.introspector;
/**
 * @author zzuhkp
 * @date 2020-05-29 17:41
 * @since 1.0
 */
public class PersonBean {
    public String getWork() {
        return null;
    }
}2


创建子类 UserBean

package com.zuhkp.java.basic.introspector;
/**
 * Java Bean
 *
 * @author zzuhkp
 * @date 2020-05-28 17:35
 * @since 1.0
 */
public class UserBean extends PersonBean {
    /**
     * 只有 writeMethod 方法的属性 name
     *
     * @param name
     */
    public void setName(String name) {
    }
    /**
     * 只有 readMethod 的属性 age
     *
     * @return
     */
    public Integer getAge() {
        return null;
    }
    /**
     * writeMethod 方法参数类型可以为 writeMethod 方法返回值类型的子类
     *
     * @param age
     */
    public void setAge(Integer age) {
    }
    /**
     * 同时具有 readMethod 和 writeMethod 方法的属性 health
     * <p>
     * 该方法为 readMethod 方法
     * <p>
     * readMethod 方法可以是以 is 开头并且返回值为 boolean 类型的方法或者是 以 get开头的方法
     *
     * @return
     */
    public boolean isHealth() {
        return false;
    }
    /**
     * 同时具有 readMethod 和 writeMethod 方法的属性 health
     * <p>
     * 该方法为 writeMethod 方法
     *
     * @param health
     */
    public void setHealth(boolean health) {
    }
    /**
     * 非表示属性的方法
     */
    public void doWork() {
    }
}


至此,我们的类型为 UserBean 的 JavaBean 已经创建完毕,那么如何获取它的属性信息呢?

先看一个手动获取的方法

package com.zuhkp.java.basic.introspector;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
/**
 * java内省示例
 *
 * @author zzuhkp
 * @date 2020-05-28 17:33
 * @since 1.0
 */
public class IntrospectorDemo {
    public static void main(String[] args) throws IntrospectionException {
        PropertyDescriptor ageProperty = new PropertyDescriptor("age", UserBean.class, "getAge", "setAge");
        System.out.println(ageProperty);
    }
}


打印结果如下:

java.beans.PropertyDescriptor[name=age; propertyType=class java.lang.Integer; readMethod=public java.lang.Integer com.zuhkp.java.basic.introspector.UserBean.getAge(); writeMethod=public void com.zuhkp.java.basic.introspector.UserBean.setAge(java.lang.Integer)]

属性名称,属性类型,读方法和写方法一目了然。age属性的描述对象由我们手工创建,如果有几十个属性,创建还是比较累的,手工创建的描述对象读方法的返回值类型和写方法的参数类型必须保持一致,否则将抛出异常。而使用 Introspector 则可以更快捷的获取 JavaBean 的所有属性,并且写方法的参数类型只要为读方法返回值类型的子类即可。下面看如何使用Introspector获取 JavaBean 的所有属性信息。


修改我们的测试类 IntrospectorDemo 为如下代码

package com.zuhkp.java.basic.introspector;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.util.stream.Stream;
/**
 * java内省示例
 *
 * @author zzuhkp
 * @date 2020-05-28 17:33
 * @since 1.0
 */
public class IntrospectorDemo {
    public static void main(String[] args) throws IntrospectionException {
        BeanInfo beanInfo = Introspector.getBeanInfo(UserBean.class, Object.class);
        Stream.of(beanInfo.getPropertyDescriptors()).forEach(System.out::println);
    }
}


打印结果如下:

java.beans.PropertyDescriptor[name=age; propertyType=class java.lang.Integer; readMethod=public java.lang.Integer com.zuhkp.java.basic.introspector.UserBean.getAge(); writeMethod=public void com.zuhkp.java.basic.introspector.UserBean.setAge(java.lang.Integer)]
java.beans.PropertyDescriptor[name=health; propertyType=boolean; readMethod=public boolean com.zuhkp.java.basic.introspector.UserBean.isHealth(); writeMethod=public void com.zuhkp.java.basic.introspector.UserBean.setHealth(boolean)]
java.beans.PropertyDescriptor[name=name; propertyType=class java.lang.String; writeMethod=public void com.zuhkp.java.basic.introspector.UserBean.setName(java.lang.String)]
java.beans.PropertyDescriptor[name=work; propertyType=class java.lang.String; readMethod=public java.lang.String com.zuhkp.java.basic.introspector.PersonBean.getWork()]


可以看到,我们不仅获取了子类的属性,而且获取了父类中的属性,并且读方法和写方法并不要求同时存在,而不满足属性方法规范的方法doWork则不作为work的读方法或者写方法。


JavaBean 方法:

JavaBean 的公共方法在 Java 中使用类 MethodDescriptor 描述,一个 JavaBean 可以包含多个 MethodDescriptor 。


JavaBean 方法来源

JavaBean的方法为包含父类和自身的公共方法,底层调用了反射中的方法 java.lang.Class#getMethods获取。


如何使用 Introspector获取 MethodDescriptor

修改测试类如下:

package com.zuhkp.java.basic.introspector;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.util.stream.Stream;
/**
 * java内省示例
 *
 * @author zzuhkp
 * @date 2020-05-28 17:33
 * @since 1.0
 */
public class IntrospectorDemo {
    public static void main(String[] args) throws IntrospectionException {
        BeanInfo beanInfo = Introspector.getBeanInfo(UserBean.class);
        Stream.of(beanInfo.getMethodDescriptors()).forEach(System.out::println);
    }
}


程序执行结果如下:

java.beans.MethodDescriptor[name=getWork; method=public java.lang.String com.zuhkp.java.basic.introspector.PersonBean.getWork()]
java.beans.MethodDescriptor[name=setAge; method=public void com.zuhkp.java.basic.introspector.UserBean.setAge(java.lang.Integer)]
java.beans.MethodDescriptor[name=setName; method=public void com.zuhkp.java.basic.introspector.UserBean.setName(java.lang.String)]
java.beans.MethodDescriptor[name=getAge; method=public java.lang.Integer com.zuhkp.java.basic.introspector.UserBean.getAge()]
java.beans.MethodDescriptor[name=isHealth; method=public boolean com.zuhkp.java.basic.introspector.UserBean.isHealth()]
java.beans.MethodDescriptor[name=doWork; method=public void com.zuhkp.java.basic.introspector.UserBean.doWork()]
java.beans.MethodDescriptor[name=setHealth; method=public void com.zuhkp.java.basic.introspector.UserBean.setHealth(boolean)]

可以看到已经成功打印出所有的公共方法。


JavaBean 事件:

JavaBean 的中的事件信息使用类 EventSetDescriptor 描述,一个 JavaBean 可以包含多个 EventSetDescriptor 。事件信息主要包括添加事件监听器方法、移除事件监听器方法、获取事件监听器列表方法。


JavaBean 中的事件监听器相关方法规范

添加事件监听器方法

方法返回值:必须为 void 。

方法名称:必须以 add 开头,以唯一的方法参数的类型名称结尾。

方法参数:只能有一个参数类型为 EventListener 接口实现类的参数。

其他限制:方法必须有对应的 remove 方法,否则该方法不构成 添加 JavaBean 添加事件监听器的方法。

移除事件监听器方法

方法返回值:必须为 void 。

方法名称:必须以 remove 开头,以唯一的方法参数的类型名称结尾。

方法参数:只能有一个参数类型为 EventListener 接口实现类的参数。

其他限制:方法必须有对应的 add 方法,否则该方法不构成 添加 JavaBean 添加事件监听器的方法。

获取事件监听器列表方法

方法返回值:方法的返回值必须为数组,数组的元素类型必须为 EventListener 接口的实现类。

方法名称:必须以 get 开头,紧跟其后的应为返回值元素类型的名称,然后后面紧跟一位字符,如 getClickedEventListeners 。

方法参数:无参数。

如何使用 Introspector 获取 EventSetDescriptor

为 UserBean 添加方法如下:

package com.zuhkp.java.basic.introspector;
/**
 * Java Bean
 *
 * @author zzuhkp
 * @date 2020-05-28 17:35
 * @since 1.0
 */
public class UserBean extends PersonBean {
    /**
     * Java Bean 添加事件监听器的方法
     * <p>
     * 方法的返回值只能为 void
     * <p>
     * 方法只能有一个类型为EventListener实现类的参数
     * <p>
     * 方法名称以 add 开头,以参数类型的名字结尾
     * <p>
     * 方法必须有对应的remove方法
     *
     * @param userEventListener
     */
    public void addUserEventListener(UserEventListener userEventListener) {
    }
    /**
     * Java Bean 移除事件监听器的方法
     * <p>
     * 方法的返回值只能为 void
     * <p>
     * 方法只能有一个类型为EventListener实现类的参数
     * <p>
     * 方法名称以 remove 开头,以参数类型的名字结尾
     *
     * @param userEventListener
     */
    public void removeUserEventListener(UserEventListener userEventListener) {
    }
    /**
     * Java Bean 获取事件监听器列表的方法
     * <p>
     * 方法的返回值必须为数组,数组的元素类型必须为 EventListener 接口的实现类
     * <p>
     * 方法名必须以 get 开头,紧跟其后的应为返回值元素类型的名称,然后后面紧跟一位字符
     * <p>
     * 方法必须无参数
     *
     * @return
     */
    public UserEventListener[] getUserEventListeners() {
        return null;
    }
}


修改测试类如下:

package com.zuhkp.java.basic.introspector;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.util.stream.Stream;
/**
 * java内省示例
 *
 * @author zzuhkp
 * @date 2020-05-28 17:33
 * @since 1.0
 */
public class IntrospectorDemo {
    public static void main(String[] args) throws IntrospectionException {
        BeanInfo beanInfo = Introspector.getBeanInfo(UserBean.class, Object.class);
        Stream.of(beanInfo.getEventSetDescriptors()).forEach(System.out::println);
    }
}


执行结果如下:

java.beans.EventSetDescriptor[name=userEvent; inDefaultEventSet; listenerType=class com.zuhkp.java.basic.introspector.UserEventListener; getListenerMethod=public com.zuhkp.java.basic.introspector.UserEventListener[] com.zuhkp.java.basic.introspector.UserBean.getUserEventListeners(); addListenerMethod=public void com.zuhkp.java.basic.introspector.UserBean.addUserEventListener(com.zuhkp.java.basic.introspector.UserEventListener); removeListenerMethod=public void com.zuhkp.java.basic.introspector.UserBean.removeUserEventListener(com.zuhkp.java.basic.introspector.UserEventListener)]

可以看到已经获取到了 JavaBean 中的事件监听器类型,添加、移除、获取事件监听器的方法。

目录
相关文章
|
8月前
|
安全 Java 编译器
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
杭州 【Java基础知识 11】java泛型方法的定义和使用(学习+改进+自己理解,想法) (借鉴-侵-删)
61 1
|
8月前
|
Java API 计算机视觉
Java数字图像处理基础知识 - 必读
Java数字图像处理基础知识 - 必读
33 0
|
8月前
|
Java 调度 开发者
Java中的多线程编程:基础知识与实践
【6月更文挑战第4天】本文深入探讨了Java中多线程编程的基础知识和实践,旨在帮助读者理解并掌握如何在Java中有效地使用多线程。我们将从线程的基本概念开始,然后介绍如何在Java中创建和管理线程,最后通过一些实际的例子来展示多线程编程的应用。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。
48 0
|
9月前
|
Java 调度
Java中的多线程编程:基础知识与实践
【5月更文挑战第31天】本文将深入探讨Java中的多线程编程,从基础知识到实践应用,全面解析多线程的概念、创建、同步以及在实际应用中的运用。我们将通过实例来展示如何在Java中有效地使用多线程,以提高程序的性能和响应速度。
|
9月前
|
监控 IDE Java
Java中的多线程编程:基础知识与实践
【5月更文挑战第30天】 在现代软件开发中,多线程编程是提高应用程序性能和响应能力的关键。特别是在Java这样的多平台、多用途的编程语言中,掌握多线程技术至关重要。本文旨在为读者提供有关Java多线程编程的全面介绍,从基本概念到高级应用技巧,帮助初学者和有经验的开发者理解并有效使用多线程。文章不仅涉及基础理论,还包括代码示例和最佳实践,确保读者能够将知识应用于实际项目中。
|
9月前
|
存储 自然语言处理 Java
Java基础之计算机基础知识引出Java
计算机基础知识概览:探讨计算机科学的约定性,指出其底层基于二进制逻辑运算,由晶体管开关控制。二进制与十进制间的转换是基础,计算机通过ASCII编码处理英文字符,但不包含汉字。早期计算机发展始于西方,从巴贝奇的差分机到图灵机,再到冯·诺伊曼结构。Unicode标准解决多语言字符编码,如UTF-8和UTF-16。编程语言分为低级(如汇编)和高级(如Java),以适应不同需求。
35 0
|
9月前
|
存储 自然语言处理 Java
Java基础之计算机基础知识了解
计算机基础知识概要: 计算机并非传统科学,其基础是二进制系统,由&#39;0&#39;和&#39;1&#39;组成,类似阴阳之道。二进制通过转换为十进制便于理解,如二进制1100等于十进制12。ASCII编码用7位二进制表示128个字符,包括字母、数字和符号。Unicode标准解决全球字符需求,UTF-8和UTF-16是常见编码格式。计算机始于查尔斯·巴贝奇的设想,经艾伦·图灵和约翰·冯·诺伊曼等人的贡献,历经晶体管和集成电路的发展,现正迈向量子计算时代。编程语言分为低级(如汇编、机器语言)和高级语言(如Java),以适应不同场景和效率需求。
32 0
|
9月前
|
Java 调度 开发者
Java中的多线程编程:基础知识与实践
【5月更文挑战第29天】 在现代软件开发中,多线程编程是一个不可忽视的领域。特别是在Java这种广泛使用的编程语言中,掌握多线程的概念和技术对于开发高效、响应迅速的应用程序至关重要。本文将深入探讨Java多线程的核心概念、实现机制以及常见问题的解决方案。我们将从基础出发,逐步揭示如何通过多线程提升程序性能,并且讨论并发编程中的挑战和解决策略。文章的目的是为开发者提供一个清晰的多线程编程指南,帮助他们在实际项目中有效地应用这些知识。
49 3
|
9月前
|
Java 程序员 调度
Java中的多线程编程:基础知识与实践
【5月更文挑战第28天】 在现代计算机科学中,多线程编程是一个重要的概念,它允许程序同时执行多个任务。在Java中,多线程编程是通过创建并管理线程来实现的。本文将介绍Java中多线程编程的基础知识,包括线程的概念、创建和控制线程的方法,以及线程同步和通信的相关技术。通过阅读本文,读者将对Java中的多线程编程有一个全面的了解,并能在实际编程中应用这些知识。
|
9月前
|
Java 调度
Java中的多线程编程:基础知识与实践
【5月更文挑战第27天】本文旨在探讨Java中的多线程编程,包括其基础知识和实践应用。我们将首先介绍多线程的基本概念,然后深入探讨如何在Java中创建和管理线程,以及如何使用同步机制来防止数据竞争。最后,我们将通过一个实例来演示如何在实际项目中应用多线程技术。

热门文章

最新文章