`

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

 
阅读更多

缘起 (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类的遍历。


 

分享到:
评论

相关推荐

    j_8243_HiMessage留言簿javabean-struts

    对于显示留言,可以使用`&lt;s:iterator&gt;`遍历JavaBean中的留言列表,并用`&lt;s:property&gt;`标签显示各项属性。 这个项目的文件`downcode.com`可能是源代码的下载链接或者是项目打包后的文件名。在实际的开发环境中,除了...

    s:iterator的EL表达式原理

    JSP2.0引入了EL表达式,使得开发者可以在JSP页面中直接引用JavaBean的属性,大大减少了JSP页面中的Java脚本代码。EL表达式采用`${}`包围,可以直接访问作用域内的变量和对象属性。例如,`${feed.title}`将获取并显示...

    计算机遍历Map集合.pdf

    1. **使用EL表达式遍历Map集合**:EL表达式可以直接在JSP页面上访问JavaBean和Map集合。 ```jsp ${map}" var="m"&gt; 键:${m.key} 值:${m.value} ``` 2. **遍历Map集合(值是对象)**:当Map的值是自定义对象时,...

    struts2标签

    它可以接受一个值(如字符串,逗号分隔的列表)或利用`count`属性指定元素数量,生成对应的迭代器,然后配合`&lt;s:iterator&gt;`遍历输出。 Struts2标签库的优势在于,它将Java代码从JSP页面中分离出来,提高了代码的...

    Java基础总结.pdf

    7. BeanUtils的copyProperties方法:此方法在Apache Commons BeanUtils库中,它用于将一个JavaBean的属性拷贝到另一个JavaBean中。 8. StringBuffer类:它是Java中用于可变字符串的类,提供了append()和insert()等...

    struts 标签手册 chm

    比如,使用`s:form`创建表单,`s:select`创建下拉列表,`s:checkbox`和`s:radiobutton`处理复选框和单选按钮,以及如何利用`s:iterator`遍历集合并展示数据。 9. **错误和异常处理** Struts标签支持错误和异常的...

    Struts2标签库.pdf

    例如,通过&lt;s:iterator value="%{#myAppendIterator}"&gt;可以遍历一个自定义的迭代器对象,其中myAppendIterator可能是一个JavaBean的属性,或者是由多个集合组合而成的新集合。在迭代过程中,可以通过标签向标签传递...

    类似百度的分页工具类,可直接用于项目开发

    EL表达式是JSP 2.0引入的一种轻量级脚本语言,用于获取和设置JavaBean属性。Struts2的`s:iterator`和`s:url`标签可以帮助遍历查询结果并构建分页链接。 例如,使用Struts2的`s:iterator`遍历分页结果: ```jsp &lt;s:...

    Strust1标 Strust1标签Strust1标签Strust1标签

    例如,`&lt;s:property&gt;`标签用于显示模型对象的属性值,`&lt;s:form&gt;`标签用于创建表单,`&lt;s:action&gt;`标签用于触发Action,以及`s:iterator&gt;`标签用于遍历集合等。 二、Struts1核心标签 1. `&lt;s:property&gt;`:此标签用于...

    struts2:我想用struts标签来统计购物车的总价

    - `${}`表示EL表达式,用于在JSP/HTML页面中访问JavaBean的属性或执行简单的运算。 #### 七、总结 通过上述代码实现,我们可以看到Struts2标签的强大之处,它不仅能够帮助我们简洁高效地完成页面数据的展示和处理...

    struts2标签库详解

    合并后的结果会存储在指定的ID中,然后可以通过`&lt;s:iterator&gt;`遍历这个合并后的结果。 2. **数据标签**: 数据标签如`&lt;s:bean&gt;`、`&lt;s:push&gt;`和`&lt;s:i18n&gt;`负责管理数据的获取和创建。`&lt;s:bean&gt;`标签可以用来实例化...

    史上最全的struts2标签

    6. **bean** 标签:用于创建JavaBean实例,如`&lt;s:bean&gt;`标签可以实例化并设置JavaBean的属性。 7. **checkbox** 标签:它生成一个HTML复选框,等同于HTML的`&lt;input type="checkbox"&gt;`。例如,`性别" name="user.sex...

    在struts2中要实现for循环

    - **使用自定义对象**:如果需要更复杂的逻辑,可以创建自定义的JavaBean对象并将其放入集合中进行遍历。 ### 示例代码 下面是一个完整的示例代码,展示了如何使用`&lt;s:iterator&gt;`标签配合`Counter` Bean实现For...

    struts1 table标签中Logic的使用属性

    ### Struts1 Table标签中Logic的使用属性 在Struts框架中,`table`标签用于在JSP页面中展示数据,而`Logic`标签则提供了条件判断的能力,这对于动态显示内容非常有用。以下是对给定文件中提到的Logic标签属性进行...

    struts2 标签

    例如,通过`val`属性指定字符串,`generator`标签可以将其解析为迭代器,然后用`s:iterator`标签遍历并输出。 Struts2标签库极大地简化了视图层的开发,提高了代码的可读性和可维护性。它们允许开发者以声明式的...

    struts2中OGNL的一些概念及原理说明

    在实际项目中,使用Struts2提供的迭代标签`&lt;s:iterator&gt;`可以在页面上方便地遍历集合。例如,要遍历一个客户列表,可以这样使用: ```xml &lt;s:iterator value="customerList" var="customer"&gt; &lt;/s:iterator&gt; ``` ...

    java web 标签大全

    - `&lt;s:iterator&gt;`:遍历集合对象。 - `&lt;s:if&gt;`和`&lt;s:else&gt;`:条件判断。 - `&lt;s:property&gt;`:显示对象的属性值。 5. Tiles标签库 Tiles库用于构建可重用的页面布局,通过定义和组合多个小部件(tiles)来创建...

    struts_分页显示数据

    4. **视图组件**:使用JSP作为视图,通过Struts的标签库,如`s:iterator`,遍历请求中的`Book[]`数组来显示数据。同时,标签库还可以用来处理分页链接,让用户能够跳转到不同的页面。在这个例子中,视图文件是`...

    java Struts 实现学生管理系统

    在Struts中,我们可以使用`struts标签库`来简化页面的开发,如`&lt;s:form&gt;`用于创建表单,`&lt;s:textfield&gt;`和`s:submit`用于输入字段和提交按钮,而`&lt;s:iterator&gt;`则用于遍历并显示列表数据。 此外,Struts框架还支持...

Global site tag (gtag.js) - Google Analytics