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)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...
随机推荐
- Educational Codeforces Round 6 E dfs序+线段树
题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...
- asp.net identity 3.0.0 在MVC下的基本使用 序言
本人也尚在学习使用之中,错误之处请大家指正. 开发环境:vs2015 UP1 项目环境:asp.net 4.6.1 模板为:asp.net 5 模板 identity版本为:asp.n ...
- JAVA修饰符
修饰符用来定义类.方法或者变量,通常放在语句的最前端.我们通过下面的例子来说明: public class className { // ... } private boolean myFlag; s ...
- springmvc配置多视图 - tiles, velocity, freeMarker, jsp
转自: http://www.cnblogs.com/shanheyongmu/p/5684595.html <!-- Velocity --> <bean id="vel ...
- h5网站和好看的动画网址
http://www.sucai888.com/data/batchzip/unzips/2165/index.html http://www.1000zhu.com
- JQuery导航选择特效
一.实现效果 1.初始化效果:未添加样式和特效 2.添加CSS样式 3.最终效果 二.JQuery代码 <!--编写JQuery代码--> <script type="te ...
- ceph network introduce
网络结构 Ceph 使用以太网连接内部各存储节点以及连接 client 和集群.Ceph 推荐使用两个网络: 前端(北向)网络( a public (front-side) network):连接客户 ...
- iOS -Swift 3.0 -for(循环语句用法)
// // ViewController.swift // Swift-循环语句 // // Created by luorende on 16/12/08. // Copyright © 2016年 ...
- lua下的简单OO实现
笔者学习了当前(文末各文献)lua下的各种OO实现方法.略作笔记. 也提出了一些自己的想法.主要还是记录供将来着之参考. 1.概述 首先[2]PIL第二版中给出了OO的基于table的实现方式 ...
- ASP.Net中的Web Resource
http://support.microsoft.com/kb/910442,这是中文的,机器翻译的,不太容易看懂,英文的是:http://support.microsoft.com/kb/91044 ...