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)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...
随机推荐
- JS for循环 闭包
对于for循环的闭包问题的理解,认为需要理解函数中的变量的作用域链的概念 另外提及下变量提升的概念 如下例子: var ar = [];for(var i=1:i<10; i++){ ar[i] ...
- float导致父级元素塌陷的问题
利用float进行页面布局时常常会出现父级元素没有高度的塌陷问题,如以下代码: <!DOCTYPE html> <html> <head lang="en&qu ...
- QtAlgorithms
qSort() qCopy() qFill() #include <QCoreApplication> #include<QDebug> #include<QVector ...
- mssql java 运行
public void rlgy() throws IOException { Statement sql; ResultSet rs; String driverName = "com.m ...
- 在java中获取attr的值
首先说如何获取已经在style里面定义好的attr的值,以colorPrimary为例: TypedValue value = new TypedValue(); mContext.getTheme( ...
- iOS duplicate symbol 变量 in 类名 报错
该错误信息是我在一个.h文件里申明了公共变量,然后在其他类里重复使用. Build Settings ->No Common Blocks默认为YES,编译器就报错了,需要修改Build Set ...
- Quartz2D 编程指南(三)渐变、透明层 、数据管理
概览 图形上下文 路径 颜色与颜色空间 变换 图案 阴影 渐变 透明层 Quartz 2D 中的数据管理 位图与图像遮罩 CoreGraphics 绘制 Layer 渐变 简介 渐变是从一个颜色到另外 ...
- Spring原理解析-利用反射和注解模拟IoC的自动装配
- Computop支付网关(一) credit Card
1.界面没有中文,只能选择英文 sp – Spanish; en – English; ca – Catalan; fr – French; de – German; du – Dutch; it – ...
- csuoj 1119: Collecting Coins
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1119 1119: Collecting Coins Time Limit: 3 Sec Memo ...