Java设计模式(二)——迭代模式
迭代模式的基本定义:对于一组对象集合(数组、堆栈、列表或散列),用户无需关心它的底层实现而能够通过调用统一接口遍历当中的所有元素。由于jdk已经对常见的迭代模式实现了封装,本文直接提供Collection和Iterator两个接口的模拟。
定义Iterator接口
/*
* 设计迭代接口
*/
public interface Iterator<E> {
// 测试是否有下一个元素
boolean hasNext();
// 返回下一个元素
E next();
}
Iterator.java
定义Collection接口
/*
* 设计一个集合对象
*/
public interface Collection<E> {
void add(E e);
E get(int index);
int size();
// 要求实现类根据自身的特点实现迭代方法
Iterator<E> iterator();
}
Collection.java
对于任何实现了接口的集合都能很方便的查找或遍历其中的元素。
创建使用数组方式存放元素集合的类:ArrayList
/*
* 模拟jdk中ArrayList的实现
*/
public class ArrayList<E> implements Collection<E>, Iterator<E> {
// 迭代下标
private int iteratorIndex = 0;
// 初始化的数组大小
private Object[] objects = new Object[10];
// 数组下标
private int index = 0; @Override
public void add(E e) {
if (index == objects.length) {
// 数组的增长的步长为10
Object[] newObjects = new Object[objects.length + 10];
System.arraycopy(objects, 0, newObjects, 0, objects.length);
objects = newObjects;
}
objects[index] = e;
index++;
} // 通过ArrayList读取元素是一次性的,开销较小
@Override
public E get(int index) {
if (index < this.index) {
return (E) objects[index];
} else {
return null;
}
} @Override
public int size() {
return index;
} @Override
public Iterator<E> iterator() {
return this;
} @Override
public boolean hasNext() {
if (iteratorIndex < index) {
return true;
} else {
return false;
}
} @Override
public E next() {
if (iteratorIndex < index) {
E e = get(iteratorIndex);
iteratorIndex++;
return e;
} else {
return null;
}
}
}
ArrayList.java
创建使用链表方式存放元素集合的类:LinkedList
package iterator.jdk;
/*
* 模拟jdk中LinkedList的实现
*/
public class LinkedList<E> implements Collection<E>, Iterator<E> {
// 迭代下标
private int iteratorIndex = 0;
// 链表长度,随元素的数量逐步递增
private int len = 0; private Node<E> headNode;
private Node<E> tailNode;
private Node<E> point; // 内部类实现链表对象的存储
private class Node<E> {
E e;
Node<E> next; Node(E e, Node<E> next) {
this.e = e;
this.next = next;
} public Object get() {
return e;
} public Node<E> getNext() {
return next;
} public void setNext(Node<E> next) {
this.next = next;
}
} @Override
public void add(E e) {
// len==0既是把头元素放入也是将链表初始化
if (len == 0) {
headNode = new Node<E>(e, null);
tailNode = headNode;
point = headNode;
len++;
} else {
Node<E> node = new Node<E>(e, null);
tailNode.setNext(node);
tailNode = node;
len++;
}
} // 通过LinkedList每次读取元素都是一次迭代的过程,开销较大
@Override
public E get(int index) {
if (index == 0) {
return (E) headNode.get();
} else if (index > 0 && index < this.len) {
Node<E> node = headNode;
for (int i = 1; i <= index; i++) {
node = node.getNext();
}
return (E) node.get();
} else {
return null;
}
} @Override
public int size() {
return len;
} @Override
public Iterator<E> iterator() {
return this;
} @Override
public boolean hasNext() {
if (iteratorIndex < len) {
return true;
} else {
return false;
}
} @Override
public E next() {
if (iteratorIndex < len) {
E e = (E) point.get();
point = point.getNext();
iteratorIndex++;
return e;
} else {
return null;
}
} }
LinkedList.java
附A:JDK容器分类

附B:HashMap模拟实现
ArrayList遍历和查询持有对象更加敏捷,但是执行插入和移除操作没有LinkedList高效,反之亦如此。如何能够结合双方的优点实现更加高效的集合容器呢?Set采用的链表数组算法更优秀,Set底层依靠Map作为实现,这里提供HashMap的模拟。
1)新建MapEntry
package containers; import java.util.*;
/*
* 键-值对模型类
*/
public class MapEntry<K, V> implements Map.Entry<K, V> {
private K key;
private V value; public MapEntry(K key, V value) {
this.key = key;
this.value = value;
} @Override
public K getKey() {
return key;
} @Override
public V getValue() {
return value;
} @Override
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
} // 重写对象hashCode值,更正规的写法应该要考虑到key==null或value==null的情况并分别处理。
@Override
public int hashCode() {
if (key != null && value != null) {
return key.hashCode() ^ value.hashCode();
}
return 0;
} @Override
public boolean equals(Object obj) {
if (obj instanceof MapEntry) {
MapEntry mapEntry = (MapEntry) obj;
return key.equals(mapEntry.getKey()) && value.equals(mapEntry.getValue());
}
return false;
} @Override
public String toString() {
return key + "=" + value;
} }
MapEntry.java
2)通过MapEntry存储键-值对实现HashMap
package containers; import java.util.*; /*
* HashMap的底层是一种链表数组的结构,依靠hashCode值取余确定数组下标,相同下标的对象依靠链表维护
* 由此可见HashMap本质上无法保证元素加载顺序
*/
public class SimpleHashMap<K, V> extends AbstractMap<K, V> {
// 设定数组长度
private static final int SIZE = 999;
// 初始化一个链表数组
private LinkedList<MapEntry<K, V>>[] slots = new LinkedList[SIZE]; public V put(K key, V value) {
// 返回值
V oldValue = null;
int index = Math.abs(key.hashCode()) % SIZE;
// 如果数组槽位为空则在当前槽位新建一个空列表
if (slots[index] == null) {
slots[index] = new LinkedList<MapEntry<K, V>>();
}
// 返回当前槽位链表
LinkedList<MapEntry<K, V>> slot = slots[index];
MapEntry<K, V> mapEntry = new MapEntry<K, V>(key, value);
// 遍历整条链表,如果找到key值则覆盖,否则新增
ListIterator<MapEntry<K, V>> it = slot.listIterator();
while (it.hasNext()) {
MapEntry<K, V> me = it.next();
if (me.getKey().equals(key)) {
oldValue = me.getValue();
// 覆盖
it.set(mapEntry);
return oldValue;
}
}
slots[index].add(mapEntry);
return oldValue;
} // 获取value的步骤是先命中槽位再遍历链表
public V get(Object key) {
int index = Math.abs(key.hashCode()) % SIZE;
if (slots[index] != null) {
for (MapEntry<K, V> me : slots[index]) {
if (me.getKey().equals(key)) {
return me.getValue();
}
}
}
return null;
} // 返回Set的步骤是先过滤空槽位再分别加载链表
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
Set<Map.Entry<K, V>> set = new HashSet<Map.Entry<K, V>>();
for (LinkedList<MapEntry<K, V>> slot : slots) {
if (slot != null) {
set.addAll(slot);
}
}
return set;
} }
SimpleHashMap.java
Java设计模式(二)——迭代模式的更多相关文章
- Java 设计模式之工厂模式(二)
原文地址:Java 设计模式之工厂模式(二) 博客地址:http://www.extlight.com 一.背景 本篇内容是 Java 设计模式创建型模式的第二篇.上一篇主题为 <Java 设计 ...
- 浅析JAVA设计模式之工厂模式(二)
1 工厂方法模式简单介绍 工厂方法 (Factroy Method)模式:又称多态性工厂模式(Polymorphic Factory),在这样的模式中,核心工厂不再是一个详细的类.而是一个抽象工厂,提 ...
- 浅析JAVA设计模式之工厂模式(一)
1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...
- Java设计模式之代理模式(静态代理和JDK、CGLib动态代理)以及应用场景
我做了个例子 ,需要可以下载源码:代理模式 1.前言: Spring 的AOP 面向切面编程,是通过动态代理实现的, 由两部分组成:(a) 如果有接口的话 通过 JDK 接口级别的代理 (b) 如果没 ...
- Java 设计模式之建造者模式(四)
原文地址:Java 设计模式之建造者模式(四) 博客地址:http://www.extlight.com 一.前言 今天继续介绍 Java 设计模式中的创建型模式--建造者模式.上篇设计模式的主题为 ...
- java设计模式3——建造者模式
java设计模式3--建造者模式 1.建造者模式介绍: 建造者模式属于创建型模式,他提供了一种创建对象得最佳方式 定义: 将一个复杂对象的构建和与它的表示分离,使得同样的构建过程可以创建不同的表示 主 ...
- 从源码角度理解Java设计模式——装饰者模式
一.饰器者模式介绍 装饰者模式定义:在不改变原有对象的基础上附加功能,相比生成子类更灵活. 适用场景:动态的给一个对象添加或者撤销功能. 优点:可以不改变原有对象的情况下动态扩展功能,可以使扩展的多个 ...
- Java设计模式——装饰者模式
JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...
- Java 设计模式(二)-六大原则
Java 设计模式(二)-六大原则 单一职责原则(Single Responsibility Principle) 定义: 不要存在多余一个原因导致类变更,既一个类只负责一项职责. 问题由来: 当类A ...
- JAVA设计模式--装饰器模式
装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...
随机推荐
- 为什么匿名内部类的参数必须为finalhttp://feiyeguohai.iteye.com/blog/1500108
1) 从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方法内部(可出现在形式参数定义处或者方法体处),因而访问方法中的局部变量(形式参数或局部变量)是天经地义的.是很自 ...
- Windows 7 IE主页被篡改,如何修复?
有时我们的电脑会因为病毒的入侵,使得IE主页被篡改,然后就会被没底线的广告包围,有时用杀毒软件也不修复,那么此时应该怎么修复呢?其实很简单,只需几步,就可以让您的电脑重新清净下来. 第一步 点击“开始 ...
- ansible 安装
1.简介 ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点,实现了批量系统配置.批量程序部署. ...
- jquery的$().each,$.each的区别
在jquery中,遍历对象和数组,经常会用到$().each和$.each(),两个方法.两个方法是有区别的,从而这两个方法在针对不同的操作上,显示了各自的特点. $().each,对于这个方法,在d ...
- Ubuntu 14.04 编译安装 boost 1.58
简介 Boost is a set of libraries for the C++ programming language that provide support for tasks and s ...
- C++ 函数形参发生动态绑定时指针增长步长与静态类型一致
牛客网上的题: class A { public: long a; }; class B : public A { public: long b; }; void seta1(A* data, int ...
- 使用JMeter进行简单的压力测试
一.压力测试 顾名思义:压力测试,就是 被测试的系统,在一定的访问压力下,看程序运行是否稳定/服务器运行是否稳定(资源占用情况). 比如: 2000个用户同时到一个购物网站购物,这些用户打开页面的速 ...
- windows查看端口占用以及关闭相应的进程
开始--运行--cmd 进入命令提示符 输入netstat -ano 即可看到所有连接的PID 之后在任务管理器中找到这个PID所对应的程序如果任务管理器中没有PID这一项,可以在任务管理器中选&qu ...
- linux udev 自动挂载 SD卡/U盘
本文记录使用udev自动挂载SD卡和U盘的方法. 参考链接 http://blog.chinaunix.net/uid-26119896-id-5211736.html 添加udev规则 创建文件/e ...
- 启用CentOS6.5 64位安装时自带的MySQL数据库服务器
本人在虚拟机上又安装了一台linux机器,作为MySQL数据库服务器用,在安装时选择了系统自带的MySQL服务器端,以下是启用步骤. 首先开启mysqld服务 #service mysqld star ...