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)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...
随机推荐
- javaScript代码执行顺序
javaScript是一种描述型脚本语言,由浏览器进行动态的解析和执行. 页面加载过程中,浏览器会对页面上载入的每个js代码块进行扫描. JavaScript是一段一段的分析执行的,在分析执行同一段代 ...
- 自定义组件-IPEdit
输入IP用的.....支持windows风格显示 unit HSIPEdit; // ********************************************************* ...
- 视觉机器学习读书笔记--------SVM方法
SVM是一种二类分类模型,有监督的统计学习方法,能够最小化经验误差和最大化几何边缘,被称为最大间隔分类器,可用于分类和回归分析.支持向量机的学习策略就是间隔最大化,可形式化为一个求解凸二次规划的问题, ...
- Python 代码覆盖率统计工具 coverage.py
coverage.py是一个用来统计python程序代码覆盖率的工具.它使用起来非常简单,并且支持最终生成界面友好的html报告.在最新版本中,还提供了分支覆盖的功能. 官方网站: http://ne ...
- ACM集训的第一题
对于一群NP(2<=NP<=10)个要互送礼物的朋友,郭铮鹏要确定每个人送出的钱比收到的多多少. 在这一个问题中,每个人都准备了一些钱来送礼物,而这些钱将会被平均分给那些将收到他的礼物的人 ...
- LeetCode Reverse Vowels of a String
原题链接在这里:https://leetcode.com/problems/reverse-vowels-of-a-string/ 题目: Write a function that takes a ...
- Python开发【前端】:JavaScript
JavaScript入门 JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本 ...
- magereverse - Magento数据库表结构
Magento数据库表结构相当复杂,250多张表包含了非常多的表关联关系,让刚刚接触Magento的开发者来说真的非常头疼.往往是看到一个产品的各种属性分散在非常多的表中,找不到任何办法来取出它们的数 ...
- 手机APP开发:学JAVA转安卓APP开发是不是很容易?
成都亿合云商小编为您分享:Android开发是以Java语言为基础的,Android 虽然使用Java 语言作为开发工具,但是在实际开发中发现,还是与Java SDK 有一些不同的地方.Android ...
- XPath 节点
在 XPath 中,有七种类型的节点:元素.属性.文本.命名空间.处理指令.注释以及文档节点(或称为根节点). XPath 术语 节点(Node) 在 XPath 中,有七种类型的节点:元素.属性.文 ...