文档章节

利用Iterator模式遍历JavaBean中的属性

-_-struggle
 -_-struggle
发布于 2017/05/31 09:46
字数 948
阅读 111
收藏 0

缘起 (Motivation/intent)

JavaScript中可以遍历对象中的属性,但Java却没有这样的语言支持。例如一个普通POJO对象UserBean

public class UserBean {

    private int id;

    private String name;

    private Date birthdate;

 

   // getters & setters

}

 

现在想遍历对象中每个属性,获得如下的效果

UserBean user = new UserBean(1234, "张三", "1982-12-13");

for(Object propertyValue : user) {

     System.out.println(propertyValue);

}

 

将显示

1234

张三

1982-12-13

 

解决方案 (Solution)

使用Iterator模式。要使某个对象可以进行遍历循环操作,亦即可以适用于foreach,该对象必须实现Iterable接口。这个接口将会强制实现iterator()方法。

public class UserBean implements Iterable<Object> {

...

@Override

public Iterator<Object> iterator() {}

}

 

实现Iterator的步骤如下

1. 在iterator()方法中,实例化我们自己的Iterator实现类,这里称之为MyObjectPropertyIterator

2. 要获取任何JavaBean对象的信息,既可以利用反射,也可以利用java.beans.Introspector这个工具类来获取一个BeanInfo对象

// 2.1.1  
BeanInfo beanInfo = Introspector.getBeanInfo(user.getClass());

//    2.1.2  从BeanInfo对象中,我们可以获得一个PropertyDescriptor数组,其中就包含了bean对象中所有属性信息

           PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();


  //  2.1.3  然后用PropertyDescription的readMethod方法获得其getter和setter,最后调用invoke方法得到返回结果

            for(PropertyDescriptor propertyDescriptor : propertyDescriptors)


                Object propertyValue = propertyDescriptor.getReadMethod().invoke(targetObject);

               System.out.println(propertyValue);


            }


    // 与我们的遍历对象属性无关没有实现的必要
    @Override
    public void remove() {}







   /*如果使用反射,则代码如下:*/

//   2.2.1  
Field[] fields = user.getClass().getDeclaredFields();

//   2.2.2 遍历Field[]数组

           for(Field field : fields) {

               field.setAccessible(true); // 这句使我们可以访问似有成员变量

               Object property = field.get(user);


           }  

 

3. 利用步骤3的思路,创建我们的Iterator实现

public class MyPropertyIterator implements Iterator<Object>{
    private int index;
    private Object targetObject;
    PropertyDescriptor[] propertyDescriptors;
   

    // 通过构造器传入所要遍历的对象,即UserBean的对象
    PropertyIterator(Object targetObject) {
        this.targetObject = targetObject;
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(targetObject.getClass());
            propertyDescriptors = beanInfo.getPropertyDescriptors();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean hasNext() {
        return this.index < this.propertyDescriptors.length;
    }

    @Override
    public Object next() {
        Object propertyValue = null;
        try {
            PropertyDescriptor propertyDescriptor = propertyDescriptors[index++];
            propertyValue= propertyDescriptor.getReadMethod().invoke(targetObject);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return propertyValue;
    }

//如果用反射

public class PropertyIterator implements Iterable<Object> {
    private final Object targetObject;
    
    public PropertyIterator(final Object targetObject) {
        this.targetObject = targetObject;
    }
    
    public Iterator<Object> iterator() {
        return new PropertyIteratorImpl();
    }
    private class PropertyIteratorImpl implements Iterator<Object>{
        int index;
        Field[] fields;

        PropertyIteratorImpl() {
            try {
                fields = targetObject.getClass().getDeclaredFields();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public boolean hasNext() {
            return this.index < this.fields.length;
        }

        @Override
        public Object next() {
            Object obj = null;
            try {
                Field field = fields[index++];
                field.setAccessible(true);
                obj = field.get(targetObject);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return obj;
        }

        @Override
        public void remove() {}
    }
}

 

 

4. 在UserBean的iterator方法中,返回MyPropertyIterator的实例化对象。 

    @Override

    public Iterator<Object> iterator() {

        return new  MyPropertyIterator(this);

    }

说明 (Note)

为了简明,没有说明Iterator设计模式的实现原理,关于这部分,请参考有关设计模式的书籍,特别是GoF。或可参考java.util.LinkedList API的源代码。

 

评估 (Assessment)

对目标对象完全没有侵入性,将遍历功能与目标对象本身分离。上一个版本,让UserBean对象直接实现Itarable,虽然更直观,代码量也少,但通用型不强,有侵入性。如果不是自己创建的类,无法使用。这个版本将Iterator类的实现分离成单独一个类,使之更通用化。现在的版本已经不需要Bean对象实现Iterable接口,使得UserBean类更干净、纯粹,不牵涉和UserBeen业务无关的任何接口或抽象类,符合将变化点分离的OO设计思想。

另外,BeanInfo版本和反射版本有细微差别:BeanInfo的PropertyDescriptor通过getter读取类变量,而反射则直接读取似有成员变量。后者显得更暴力些。虽然从代码编写者的角度似乎更方便,但破坏了OO的封装和信息隐藏原则。

 

本篇笔记的目的是灵活使用Iterator模式。和大多数书本或网上教程不同,本篇利用Iterator模式实现了一个非Collection类的遍历。

本文转载自:http://akingde.iteye.com/blog/2035092

上一篇: Maven和Gradle对比
下一篇: 获取json数据长度
-_-struggle
粉丝 3
博文 210
码字总数 50914
作品 0
苏州
后端工程师
私信 提问
JavaScript 设计模式(五):迭代器模式

文章内容分两部分: 前半部分为 “迭代器模式” 概念; 后半部分为 ES6 中 Iterator (迭代器) 上半部分开始... 迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露...

以乐之名
07/01
0
0
Laravel5.2之PHP对象遍历(Iterator)

说明:本文章主要讲述PHP的对象遍历(Iterator)知识点。由于Laravel框架中就在集合(Collection)中用到了对象遍历知识点,故记录并学习之。同时,作者会将开发过程中的一些截图和代码黏上去,提...

botkenni
2016/10/24
53
0
struts2 标签的使用之一 s:if

标签: struts2 的web 项目中为了方便的编写jsp,标签是最好的选择 1:struts2 标签库的定义在**-core-版本号.jar META-INF 路径下找到struts-tags.tld文件;使用该标签需要在web 项目里面导...

肥皂泡2
2011/05/03
465
0
前端日拱一卒D10——ES6笔记之新特性篇

前言 余为前端菜鸟,感姿势水平匮乏,难观前端之大局。遂决定循前端知识之脉络,以兴趣为引,辅以几分坚持,望于己能解惑致知、于同道能助力一二,岂不美哉。 本系列代码及文档均在 此处 依然...

DerekZ95
2018/08/07
0
0
ES6标准入门之变量的解构赋值

在正式的讲解之前,我们先来分析一下,到底什么是解构赋值? 通过对词组的分析,我们大致能理解,解构---也就是破坏,破坏原来的结构,赋值---当然就是再次赋值。下面我们来具体的分析一下,...

你的声先生
05/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

自定义ApiBoot Logging链路以及单元ID生成策略

ApiBoot Logging会为每一个请求都对应创建链路编号(TraceID)以及单元编号(SpanID),用于归类每一次请求日志,通过一个链路下日志单元的Parent SpanID可以进行上下级关系的梳理。 前文回顾...

恒宇少年
17分钟前
6
0
浅谈 Application 和 activity

对于 在 Application初始化一些变量,为什么不可以放在activity 或者其他的组件里呢? 这里就根据个人的理解来讲述一下,欢迎补充指正。 首先 activity 是以栈的形式出现,一个app应用会有多...

MrLins
17分钟前
5
0
Allegro的脚本文件内容里都有哪些

小伙伴们在使用Allegro的时候是否经常用到脚本文件夹呢?scr的用法其实可真不简单。。。 首先脚本文件的运行模式就存在很多种,比如不提示错误信息,不弹出确认对画框(这样很有利于我们执行...

demyar
19分钟前
12
0
微信升级外链管理规范,「砍一刀帮我加速」要被禁止了

原创: 蒋鸿昌 首发:「知晓程序」公众号 - 最好的微信新商业媒体 几天前,知名互联网评论人阑夕模仿皮尤研究中心(Pew Research Center)在美国做的互联网通识调查问卷,做了一份中文版问卷...

知晓云
19分钟前
8
0
CentOS 7接投影仪

我将一台安装着CentOS 7图形界面的惠普笔记本电脑当桌面使用。最近,想要连接投影仪时却遇到了问题。笔记本有一个HDMI接口。我买了一个HDMI---->VGA的转接线,连上笔记本电脑后,屏幕一直在闪...

大别阿郎
23分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部