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)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...
随机推荐
- AD Local Domain groups, Global groups and Universal groups
http://ss64.com/nt/syntax-groups.html Rules that govern when a group can be added to another group ( ...
- 【5集iCore3_ADP演示视频】5-3 iCore3应用开发平台摸校准
iCore3双核心应用开发平台基于iCore3双核心板,包含ARM.FPGA.7寸液晶屏.双通道数字示波器.任意波发生器.电压表等模块,是一款专为电子爱好者设计的综合性电子学习系统. [视频简介]本视 ...
- Windows 7 常用快捷键
常用的快捷键 Win键+D 回到桌面/当前界面(切换)Win键+M 回到桌面Win键+E 资源管理器Win键+R 运行 Win键+U 控制面板->所有控制面板项->轻松访问中心 Win键+ ...
- Python格式化字符串~转
Python格式化字符串 在编写程序的过程中,经常需要进行格式化输出,每次用每次查.干脆就在这里整理一下,以便索引. 格式化操作符(%) "%"是Python风格的字符串格式化操作 ...
- 数据库访问CRUD;__SELF__和__ACTION__的区别;自动收集表单:$n->create();
一.tp框架数据访问(pdo基础) public function test() { $n = D("Nation"); //select();find(); //查询 1.$at ...
- LDA的Python实现源码
#-*- coding:utf-8 -*- import logging import logging.config import ConfigParser import numpy as np im ...
- Eclipse汉化后切换回英文
方法: 1.复制MyEclipse的快捷方式: 2.右键快捷方式->属性,在“目标”的后边加上 -nl "en" 之前的:"F:\Program Files\MyE ...
- jsp中的form表单中的 id和name有什么区别了
<form action="./system/WebServer_webServerLogin" method="post" id="login ...
- C#注解属性的感想一:
C#当中Attribute(中文注解属性)已经知道这个概念已经很久很久了,不过悲剧的是在实际项目当中重来没有用它来做过什么东西,以致对它的理解总是很浅薄,更谈不上如何在实际项目中运用它.最近在学习&l ...
- 导入excel2007文件问题
基于oledb方式导入excel2007文件时,使用如下链接字符串: string strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Sour ...