缘起 (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类的遍历。
相关推荐
NULL 博文链接:https://takeme.iteye.com/blog/1663239
其实只有一点struts2 iterator标签遍历二维数组
1. 遍历List 2. 遍历List<List<String>> 3. 遍历UserEntity 4. 遍历List 遍历方法各有长短,若不是多表联接查询、显示表格的列数已经固定,一般用实体类(UserEntity)迭代的方式。相反,显示的数据表格行和列不确定...
该文档代码讲述了如何在jsp页面iterator遍历数组、Map、List集合
Iterator接口在集合中的使用方法!
主要介绍了Java Iterator接口遍历单列集合迭代器原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
Iterator遍历中 ConcurrentModificationException异常
一段在java中使用的循环遍历集合中存储值的代码,给大家分享一下。
js中使用map形式存取遍历
jsp自定义标签iterator遍历list[整理].pdf
Java源码分析:深入探讨Iterator模式
NULL 博文链接:https://takeme.iteye.com/blog/1663039
原料药循环遍历一堆流,将每个steram的结果传递到堆栈中的下一个流。 参量stack {Array} :要使用的流的数组。 returns {Function} :返回将在给定的流堆栈上进行迭代的函数。 var fs = require ( 'fs' ) ;var ...
所谓Iterator模式,即是Iterator为不同的容器提供一个统一的访问方式。本文以java中的容器为例,模拟Iterator的原理。 参考:马士兵 Java设计模式 Iterator 1.首先定义一个容器Collection接口. 2.定义一个Iterator...
23种设计模式之二十二(行为模式)Iterator模式
计算机后端-Java-Java核心基础-第24章 集合01 08. 使用Iterator遍历Collection.avi
计算机后端-Java-Java核心基础-第24章 集合01 10. Iterator遍历集合的两种错误写法.avi
用java编写的迭代器,实现10数字正反向遍历。
主要介绍了java使用iterator遍历指定目录示例,需要的朋友可以参考下
主要介绍了Java使用Iterator迭代器遍历集合数据的方法,结合实例形式分析了java迭代器进行集合数据遍历的常见操作技巧,需要的朋友可以参考下