关于属性描述符PropertyDescriptor[通俗易懂]

关于属性描述符PropertyDescriptor[通俗易懂]本文首发于本博客猫叔的博客,转载请申明出处前言感谢GY丶L粉丝的提问:属性描述器PropertyDescriptor是干嘛用的?本来我也没有仔细了解过描述符这一块的知识,不过粉丝问了,我就抽周末的时间看看,顺便学习一下,粉丝问的刚好是PropertyDescriptor这个属性描述符,我看了下源码。/***AProper…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

本文首发于本博客
猫叔的博客,转载请申明出处

前言

感谢GY丶L粉丝的提问:属性描述器PropertyDescriptor是干嘛用的?

本来我也没有仔细了解过描述符这一块的知识,不过粉丝问了,我就抽周末的时间看看,顺便学习一下,粉丝问的刚好是PropertyDescriptor这个属性描述符,我看了下源码。

/**
 * A PropertyDescriptor describes one property that a Java Bean
 * exports via a pair of accessor methods.
 */
public class PropertyDescriptor extends FeatureDescriptor {
    //...
}

emmmm,假装自己英语能厉害的说,属性描述符描述了一个属性,即Java Bean 通过一对访问器方法来导出。(没错,他确实是存在于java.beans包下的)

描述符

通过类关系图,可以知道,我们应该提前了解一下FeatureDescriptor才行了。很好,起码目前还没有设计抽象类或者接口。

FeatureDescriptor

/**
 * The FeatureDescriptor class is the common baseclass for PropertyDescriptor,
 * EventSetDescriptor, and MethodDescriptor, etc.
 * <p>
 * It supports some common information that can be set and retrieved for
 * any of the introspection descriptors.
 * <p>
 * In addition it provides an extension mechanism so that arbitrary
 * attribute/value pairs can be associated with a design feature.
 */

public class FeatureDescriptor {
    //...
}

okay,这是很合理的设计方式,FeatureDescriptor为类似PropertyDescriptor、EvebtSetDescriptor、MethodDescriptor的描述符提供了一些共用的常量信息。同时它也提供一个扩展功能,方便任意属性或键值对可以于设计功能相关联。

这里简单的说下,在我大致看了一下源码后(可能不够详细,最近有点忙,时间较赶),FeatureDescriptor主要是针对一下属性的一些get/set,同时这些属性都是基本通用于PropertyDescriptor、EvebtSetDescriptor、MethodDescriptor。

    private boolean expert; // 专有
    private boolean hidden; // 隐藏
    private boolean preferred; // 首选
    private String shortDescription; //简单说明
    private String name; // 编程名称
    private String displayName; //本地名称
    private Hashtable<String, Object> table; // 属性表

其实该类还有另外几个方法,比如深奥的构造函数等等,这里就不深入探讨了。

PropertyDescriptor

那么我们大致知道了FeatureDescriptor,接下来就可以来深入了解看看这个属性描述符PropertyDescriptor

说到属性,大家一定会想到的就是get/set这个些基础的东西,当我打开PropertyDescriptor源码的时候,我也看到了一开始猜想的点。

    private final MethodRef readMethodRef = new MethodRef();
    private final MethodRef writeMethodRef = new MethodRef();
    private String writeMethodName;
    private String readMethodName;

这里的代码是我从源码中抽离的一部分,起码我们这样看可以大致理解,是分为写和读的步骤,那么就和我们初学java的get/set是一致的。

同时我还看到了,这个,及其注释。

    // The base name of the method name which will be prefixed with the
    // read and write method. If name == "foo" then the baseName is "Foo"
    private String baseName;

这好像可以解释,为什么我们的属性在生成get/set的时候,第一个字母变成大写?!注释好像确实是这样写的。

由于可能需要一个Bean对象,所以我以前在案例中先创建了一个Cat类。

public class Cat {

    private String name;

    private String describe;

    private int age;

    private int weight;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescribe() {
        return describe;
    }

    public void setDescribe(String describe) {
        this.describe = describe;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }
}

构造函数

起码目前,我还不知道我应该怎么使用它,那么我们就一步一步来吧,我看到它有好几个构造函数,这是一个有趣而且有难度的事情,我们先试着创建一个PropertyDescriptor吧。

  • 第一种构造函数
    /**
     * Constructs a PropertyDescriptor for a property that follows
     * the standard Java convention by having getFoo and setFoo
     * accessor methods.  Thus if the argument name is "fred", it will
     * assume that the writer method is "setFred" and the reader method
     * is "getFred" (or "isFred" for a boolean property).  Note that the
     * property name should start with a lower case character, which will
     * be capitalized in the method names.
     *
     * @param propertyName The programmatic name of the property.
     * @param beanClass The Class object for the target bean.  For
     *          example sun.beans.OurButton.class.
     * @exception IntrospectionException if an exception occurs during
     *              introspection.
     */
    public PropertyDescriptor(String propertyName, Class<?> beanClass)
                throws IntrospectionException {
        this(propertyName, beanClass,
                Introspector.IS_PREFIX + NameGenerator.capitalize(propertyName),
                Introspector.SET_PREFIX + NameGenerator.capitalize(propertyName));
    }

这个好像是参数最少的,它只需要我们传入一个属性字符串,还有对应的类就好了,其实它也是调用了另一个构造函数,只是它会帮我们默认生成读方法和写方法。方法中的Introspector.IS_PREFIX + NameGenerator.capitalize(propertyName)其实就是自己拼出一个默认的get/set方法,大家有兴趣可以去看看源码。

那么对应的实现内容,我想大家应该都想到了。

    public static void main(String[] args) throws Exception {
        PropertyDescriptor CatPropertyOfName = new PropertyDescriptor("name", Cat.class);
        System.out.println(CatPropertyOfName.getPropertyType());
        System.out.println(CatPropertyOfName.getPropertyEditorClass());
        System.out.println(CatPropertyOfName.getReadMethod());
        System.out.println(CatPropertyOfName.getWriteMethod());
    }
  • 第二种构造函数
/**
     * This constructor takes the name of a simple property, and method
     * names for reading and writing the property.
     *
     * @param propertyName The programmatic name of the property.
     * @param beanClass The Class object for the target bean.  For
     *          example sun.beans.OurButton.class.
     * @param readMethodName The name of the method used for reading the property
     *           value.  May be null if the property is write-only.
     * @param writeMethodName The name of the method used for writing the property
     *           value.  May be null if the property is read-only.
     * @exception IntrospectionException if an exception occurs during
     *              introspection.
     */
    public PropertyDescriptor(String propertyName, Class<?> beanClass,
                String readMethodName, String writeMethodName)
                throws IntrospectionException {
        if (beanClass == null) {
            throw new IntrospectionException("Target Bean class is null");
        }
        if (propertyName == null || propertyName.length() == 0) {
            throw new IntrospectionException("bad property name");
        }
        if ("".equals(readMethodName) || "".equals(writeMethodName)) {
            throw new IntrospectionException("read or write method name should not be the empty string");
        }
        setName(propertyName);
        setClass0(beanClass);

        this.readMethodName = readMethodName;
        if (readMethodName != null && getReadMethod() == null) {
            throw new IntrospectionException("Method not found: " + readMethodName);
        }
        this.writeMethodName = writeMethodName;
        if (writeMethodName != null && getWriteMethod() == null) {
            throw new IntrospectionException("Method not found: " + writeMethodName);
        }
        // If this class or one of its base classes allow PropertyChangeListener,
        // then we assume that any properties we discover are "bound".
        // See Introspector.getTargetPropertyInfo() method.
        Class[] args = { PropertyChangeListener.class };
        this.bound = null != Introspector.findMethod(beanClass, "addPropertyChangeListener", args.length, args);
    }

没错,这个构造函数就是第一种构造函数内部二次调用的,所需要的参数很简单,同时我也希望大家可以借鉴这个方法中的一些检测方式。这次的实现方式也是同样的形式。

    public static void main(String[] args) throws Exception {
        PropertyDescriptor CatPropertyOfName = new PropertyDescriptor("name", Cat.class,"getName","setName");
        System.out.println(CatPropertyOfName.getPropertyType());
        System.out.println(CatPropertyOfName.getPropertyEditorClass());
        System.out.println(CatPropertyOfName.getReadMethod());
        System.out.println(CatPropertyOfName.getWriteMethod());
    }
  • 第三种构造函数
    /**
     * This constructor takes the name of a simple property, and Method
     * objects for reading and writing the property.
     *
     * @param propertyName The programmatic name of the property.
     * @param readMethod The method used for reading the property value.
     *          May be null if the property is write-only.
     * @param writeMethod The method used for writing the property value.
     *          May be null if the property is read-only.
     * @exception IntrospectionException if an exception occurs during
     *              introspection.
     */
    public PropertyDescriptor(String propertyName, Method readMethod, Method writeMethod)
                throws IntrospectionException {
        if (propertyName == null || propertyName.length() == 0) {
            throw new IntrospectionException("bad property name");
        }
        setName(propertyName);
        setReadMethod(readMethod);
        setWriteMethod(writeMethod);
    }

这个不用传类,因为你需要传递两个实际的方法进来,所以主要三个对应属性的参数既可。看看大致的实现内容

    public static void main(String[] args) throws Exception {
        Class<?> classType = Cat.class;
        Method CatNameOfRead = classType.getMethod("getName");
        Method CatNameOfWrite = classType.getMethod("setName", String.class);
        PropertyDescriptor CatPropertyOfName = new PropertyDescriptor("name", CatNameOfRead,CatNameOfWrite);
        System.out.println(CatPropertyOfName.getPropertyType());
        System.out.println(CatPropertyOfName.getPropertyEditorClass());
        System.out.println(CatPropertyOfName.getReadMethod());
        System.out.println(CatPropertyOfName.getWriteMethod());
    }

好了,大致介绍了几种构造函数与实现方式,起码我们现在知道它需要什么。

一些使用方式

其实在我上面写一些构造函数的时候,我想大家应该已经感受到与反射相关了,起码我感觉上是这样的,所以我一开始想到这样的案例形式,通过反射与这个属性描述类去赋予我的类。

    public static void main(String[] args) throws Exception {
        //获取类
        Class classType = Class.forName("com.example.demo.beans.Cat");
        Object catObj = classType.newInstance();
        //获取Name属性
        PropertyDescriptor catPropertyOfName = new PropertyDescriptor("name",classType);
        //得到对应的写方法
        Method writeOfName = catPropertyOfName.getWriteMethod();
        //将值赋进这个类中
        writeOfName.invoke(catObj,"river");
        Cat cat = (Cat)catObj;
        System.out.println(cat.toString());
    }

运行结果还是顺利的。

Cat{name=’river’, describe=’null’, age=0, weight=0}

可以看到,我们确实得到了一个理想中的对象。

那么我是不是可以改变一个已经创建的对象呢?

    public static void main(String[] args) throws Exception {
        //一开始的默认对象
        Cat cat = new Cat("river","黑猫",2,4);
        //获取name属性
        PropertyDescriptor catPropertyOfName = new PropertyDescriptor("name",Cat.class);
        //得到读方法
        Method readMethod = catPropertyOfName.getReadMethod();
        //获取属性值
        String name = (String) readMethod.invoke(cat);
        System.out.println("默认:" + name);
        //得到写方法
        Method writeMethod = catPropertyOfName.getWriteMethod();
        //修改值
        writeMethod.invoke(cat,"copy");
        System.out.println("修改后:" + cat);
    }

上面的demo是,我先创建了一个对象,然后通过属性描述符读取name值,再进行修改值,最后输出的对象的值也确实改变了。

默认:river

修改后:Cat{name=’copy’, describe=’黑猫’, age=2, weight=4}

收尾

这是一个有趣的API,我想另外两个(EvebtSetDescriptor、MethodDescriptor)应该也差不多,大家可以再通过此方法去探究,只有自己尝试一次才能学到这里面的一些东西,还有一些项目场景的使用方式,不过一般的业务场景应该很少使用到这个API。那么这个东西究竟可以干什么呢?我想你试着敲一次也许有一些答案了。

公众号:Java猫说

现架构设计(码农)兼创业技术顾问,不羁平庸,热爱开源,杂谈程序人生与不定期干货。

Image Text

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/187216.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 安卓rom包制作_android原生rom下载

    安卓rom包制作_android原生rom下载制作ROM包是做Android系统工程师的第一步,Android第三方的市场

    2022年10月16日
  • unity麻将开发视频教程_一屏双人单机手机游戏

    unity麻将开发视频教程_一屏双人单机手机游戏小实习生一枚,刚入门unity,利用一周的时间做了个单机简单的二人小麻将只有java基础,从来没学过C#的我,刚开始很懵逼,但是既然动手做了就开始吧~!先上成品图因为公司都用比较稳定的版本,所以我是从比较老的版本unity4.7上手学习的刚开始学什么都不懂,参考了一个别人写的斗地主demo,所以代码比较累赘…你们可以改良一下二人麻将介绍牌型分为:条

  • Pytest(1)安装与入门[通俗易懂]

    Pytest(1)安装与入门[通俗易懂]pytest介绍pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高。根据pytest的官方网站介绍,它

  • 2015年职称计算机考试宝典,2015年职称计算机考试宝典模块软件.doc[通俗易懂]

    2015年职称计算机考试宝典,2015年职称计算机考试宝典模块软件.doc[通俗易懂]2015年职称计算机考试宝典模块软件2015年职称计算机考试宝典模块软件【职考宝典】是一款职称计算机考试学习题库辅导软件,包括:手把手教学一步一提示,同步答案演示帮助您高效掌握解题方法。模拟考试10套全真试题,共400道左右的真题,自动评分,考后即知成绩,错题复习帮助您查缺补漏。包含模块:WindowsXP、Word2003、Excel2003、PowerPoint2003、Internet应用W…

  • Padstart_notation pad pro

    Padstart_notation pad pro//将一个ipv4地址转换为10进制数输出//eg:192.168.1.1functiontranslateIP2Dig(ipStr){letipArr=ipStr.split(‘.’)letresArr=[]ipArr.forEach(item=>{letstr=parseInt(item).toString(2)str=str.padStart(8,0)resArr.push(str)})retu

  • 中星睿典职称计算机考试,大纲教材 – 中星睿典 – 全国职称计算机考试|职称计算机考试模块|全国职称计算机考试试题…

    中星睿典职称计算机考试,大纲教材 – 中星睿典 – 全国职称计算机考试|职称计算机考试模块|全国职称计算机考试试题…大纲教材介绍全国专业技术人员计算机应用能力考试,又称全国职称计算机应用考试。为贯彻党的十五届五中全会提出的“要在全社会广泛应用信息技术,全国职称计算机考试可以提高计算机和网络的普及应用程度,加强信息资源的开发和利用”的精神,落实国家加快信息化建设的要求,引导全国专业技术人员学习掌握计算机知识,提高计算机的应用能力,根据原人事部《关于全国专业技术人员计算机应用能力考试的通知》(人发2001124号)…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号