Java 有没有办法访问LinkedHashMap的内部节点?
我希望他们为一个集合做一个自定义迭代器Java 有没有办法访问LinkedHashMap的内部节点?,java,linkedhashmap,Java,Linkedhashmap,我希望他们为一个集合做一个自定义迭代器 (elem)中的ListIterator扩展了实现并添加了一些façade方法我现在有了一个解决方案,它不使用扩展或反射(或者实际上是LinkedHashMap) 你觉得怎么样 package i3.util; import java.util.AbstractSet; import java.util.Collection; import java.util.ConcurrentModificationException; import java.ut
(elem)中的ListIterator扩展了实现并添加了一些façade方法我现在有了一个解决方案,它不使用扩展或反射(或者实际上是LinkedHashMap) 你觉得怎么样
package i3.util;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* This class is a like LinkedHashSet (insertion order) but it allows querying
* the relative position of a element and has a ListIterator that can set and
* insert anywhere.
*
* Warning: the iterator can change the order of the set by moving elements when
* setting or adding. Elements that already exist are not ignored, but moved the
* requested place. This changes iteration order
*
*
* The iterators of this class are fail fast and will throw a
* ConcurrentModificationException if their iterator are used with intervening
* main class (or other iterators) mutative calls
*
* @author i30817 <i30817@gmail.com>
*/
public class LinkedSet<E> extends AbstractSet<E> {
//It holds the linked list
private Map<E, Node> m = new HashMap<E, Node>();
//head of that
protected Node head = new Node();
//this is copied to the map value in increments of iteratorAddStep on set.add
//(which only adds to the end, by insertion indexing)
private int monotonicallyIncreasing = 0;
//iterator add step may change when doing rebuilds of the 'space' between elements
//for the before/after functions on LinkedKeyIterator.add
private int iteratorAddStep = 10;
//for fail fast iterators
private int modCount;
/**
* Start iterating from elem (inclusive)
*
*
* @throws NoSuchElementException if E not part of the set
* @param elem a element of the set
* @return a ListIterator - doesn't support nextIndex() or previousIndex()
*/
public ListIterator<E> from(E elem) {
Node e = m.get(elem);
if (e == null) {
throw new NoSuchElementException("the given element isn't part of the set");
}
return new LinkedKeyIterator(e);
}
@Override
public ListIterator<E> iterator() {
return new LinkedKeyIterator();
}
/**
* Returns true if the value target was added before (exclusive) limitElem
* in insertion order.
*
* If target or limit are not present on the set this method returns false
*
* @param limitElem a E that may be a element of the set or not.
* @return if target was added before limit (can be reset by removing and
* re-adding the target, that changes iteration order).
*/
public boolean containsBefore(E target, E limitElem) {
if (isEmpty()) {
return false;
}
Integer targetN = m.get(target).relativeLocation;
Integer highN = m.get(limitElem).relativeLocation;
return targetN != null && highN != null && targetN < highN;
}
/**
* Returns true if the value target was added after (exclusive) previousElem
* in insertion order.
*
* If target or previous are not present on the set this method returns
* false
*
* @param previousElem a E that may be a element of the set or not.
* @return if target was added before previous (can be reset by removing and
* re-adding the target, that changes iteration order).
*/
public boolean containsAfter(E target, E previousElem) {
if (isEmpty()) {
return false;
}
Integer targetN = m.get(target).relativeLocation;
Integer low = m.get(previousElem).relativeLocation;
return targetN != null && low != null && low < targetN;
}
@Override
public boolean add(E e) {
if (!m.containsKey(e)) {
Node n = new Node(e, monotonicallyIncreasing);
monotonicallyIncreasing += iteratorAddStep;
n.addBefore(head);//insertion order
m.put(e, n);
return true;
}
return false;
}
@Override
public int size() {
return m.size();
}
@Override
public boolean isEmpty() {
return m.isEmpty();
}
@Override
public boolean contains(Object o) {
return m.containsKey(o);
}
@Override
public Object[] toArray() {
Object[] result = new Object[size()];
int i = 0;
for (E e : this) {
result[i++] = e;
}
return result;
}
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size) {
a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
}
int i = 0;
Object[] result = a;
for (E e : this) {
result[i++] = e;
}
if (a.length > size) {
//peculiar toArray contract where it doesn't care about the rest
a[size] = null;
}
return a;
}
@Override
public boolean remove(Object o) {
Node n = m.remove(o);
if (n != null) {
n.remove();
return true;
}
return false;
}
@Override
public boolean addAll(Collection<? extends E> c) {
boolean changed = false;
for (E e : c) {
changed |= add(e);
}
return changed;
}
@Override
public boolean containsAll(Collection<?> c) {
boolean all = true;
for (Object e : c) {
all &= m.containsKey(e);
}
return all;
}
@Override
public boolean retainAll(Collection<?> c) {
boolean changed = false;
Iterator<E> it = iterator();
while (it.hasNext()) {
E k = it.next();
if (!c.contains(k)) {
it.remove();
changed = true;
}
}
return changed;
}
@Override
public void clear() {
modCount++;
head.after = head.before = head;
m.clear();
}
@Override
public String toString() {
return m.keySet().toString();
}
//linkedlist node class
protected final class Node {
Node before, after;
int relativeLocation;
//needed for map removal during iteration
E key;
private void remove() {
before.after = after;
after.before = before;
modCount++;
}
private void addBefore(Node existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
modCount++;
}
//head const
public Node() {
after = before = this;
relativeLocation = 0;
}
public Node(E key, int value) {
this.key = key;
this.relativeLocation = value;
}
}
protected class LinkedKeyIterator implements ListIterator<E> {
Node nextEntry;
Node lastReturned;
int expectedModCount = modCount;
public LinkedKeyIterator() {
nextEntry = head.after;
}
public LinkedKeyIterator(Node startAt) {
nextEntry = startAt;
}
public boolean hasPrevious() {
return nextEntry.before != head;
}
public boolean hasNext() {
return nextEntry != head;
}
public E next() {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (nextEntry == head) {
throw new NoSuchElementException();
}
Node e = lastReturned = nextEntry;
nextEntry = e.after;
return e.key;
}
public E previous() {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (nextEntry.before == head) {
throw new NoSuchElementException();
}
Node e = lastReturned = nextEntry.before;
nextEntry = e;
return e.key;
}
public void remove() {
if (lastReturned == null) {
throw new IllegalStateException();
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
m.remove(lastReturned.key);
nextEntry = lastReturned.after;
lastReturned.remove();
lastReturned = null;
expectedModCount = modCount;
}
@Override
public void set(E e) {
if (lastReturned == null) {
throw new IllegalStateException();
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (lastReturned.key.equals(e)) {
return;
}
//remove mapping for key since we are changing it
m.remove(lastReturned.key);
//put in the new one
lastReturned.key = e;
Node previousKeyOwner = m.put(e, lastReturned);
if (previousKeyOwner != null) {
//as it is a list mutation call, guard against stale iterator
if(nextEntry == previousKeyOwner){
nextEntry = nextEntry.after;
}
previousKeyOwner.remove();
}
//from m.remove and m.put, may help with 2 concurrent iterators on this instance
//this method may not change modCount if previousKeyOwner is null
expectedModCount = ++modCount;
}
@Override
public void add(E e) {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
//calculate a good relative location, updating subsequent ones if needed
int candidateLoc = nextEntry.before.relativeLocation + 1;
//opsss, it's full
if (candidateLoc == nextEntry.relativeLocation) {
iteratorAddStep *= 1.6;
for (Node current = nextEntry; current != head; current = current.after) {
current.relativeLocation = current.relativeLocation + iteratorAddStep;
}
}
Node n = m.get(e);
if (n == null) {
n = new Node(e, candidateLoc);
m.put(e, n);
} else {
n.relativeLocation = candidateLoc;
//as it is a list mutation call, guard against stale iterator
if(nextEntry == n){
nextEntry = nextEntry.after;
}
n.remove();
}
n.addBefore(nextEntry);
expectedModCount = modCount;//add before changes modCount
}
@Override
public int nextIndex() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public int previousIndex() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
}
包i3.util;
导入java.util.AbstractSet;
导入java.util.Collection;
导入java.util.ConcurrentModificationException;
导入java.util.HashMap;
导入java.util.Iterator;
导入java.util.ListIterator;
导入java.util.Map;
导入java.util.NoSuchElementException;
/**
*此类类似于LinkedHashSet(插入顺序),但它允许查询
*元素的相对位置,并具有可以设置和
*插入任意位置。
*
*警告:迭代器可以通过在下列情况下移动元素来更改集合的顺序:
*设置或添加。不会忽略已存在的元素,而是将其移动到
*请求地点。这会改变迭代顺序
*
*
*该类的迭代器故障很快,将抛出
*ConcurrentModificationException,如果其迭代器用于干预
*主类(或其他迭代器)可变调用
*
*@author i30817
*/
公共类LinkedSet扩展了抽象集{
//它保存链接列表
私有映射m=新的HashMap();
//头儿
受保护的节点头=新节点();
//这将在set.add上以迭代器ADDSTEP的增量复制到映射值
//(仅通过插入索引添加到末尾)
私有int单调递增=0;
//在重建元素之间的“空间”时,迭代器添加步骤可能会更改
//对于LinkedKeyIterator.add上的before/after函数
私有int迭代器adstep=10;
//对于失败快速迭代器
私有int modCount;
/**
*从元素开始迭代(包括元素)
*
*
*@如果E不是集合的一部分,则抛出NoSuchElementException
*@param elem集合中的一个元素
*@返回ListIterator-不支持nextIndex()或previousIndex()
*/
来自(E元素)的公共列表迭代器{
节点e=m.get(elem);
如果(e==null){
抛出新的NoSuchElementException(“给定元素不是集合的一部分”);
}
返回新的LinkedKeyIterator(e);
}
@凌驾
公共列表迭代器迭代器(){
返回新的LinkedKeyIterator();
}
/**
*如果在(独占)limitElem之前添加了值目标,则返回true
*按插入顺序。
*
*如果集合上不存在目标或限制,则此方法返回false
*
*@param limitElem可能是集合中的元素,也可能不是。
*@return如果目标是在限制之前添加的(可以通过移除和
*重新添加目标,这会改变迭代顺序)。
*/
公共布尔值包含在(E目标、E限制元素)之前{
if(isEmpty()){
返回false;
}
整数targetN=m.get(target).relativeLocation;
整数highN=m.get(limitElem).相对位置;
返回targetN!=null&&highN!=null&&targetN尺寸){
//这是一个奇怪的阵列合同,它不关心其他的
a[size]=null;
}
返回a;
}
@凌驾
公共布尔删除(对象o){
节点n=m.remove(o);
如果(n!=null){
n、 删除();
返回true;
}
返回false;
}
@凌驾
公共布尔addAll(集合c){
布尔值all=true;
用于(对象e:c){
全部&=m.CONTANSKEY(e);
}
全部归还;
}
@凌驾
公共布尔保留(集合c){
布尔值=假;
迭代器it=迭代器();
while(it.hasNext()){
ek=it.next();
如果(!c.包含(k)){
it.remove();
更改=正确;
}
}
回报发生变化;
}
@凌驾
公共空间清除(){
modCount++;
head.after=head.before=head;
m、 清除();
}
@凌驾
公共字符串toString(){
返回m.keySet().toString();
}
//linkedlist节点类
受保护的最终类节点{
节点前、后;
国际关系定位;
//需要在迭代期间删除映射
E键;
私有无效删除(){
before.after=之后;
before=before;
modCount++;
}
私有void addBefore(节点existingEntry){
之后=现有条目;
before=existingEntry.before;
在此之前。之后=此;
之后。之前=这个;
modCount++;
}
//总目c
public class Map<K, V> extends HashMap<K, V> {
public Set<K, V> entrySet() {
return new HashSet<K, V>(super.entrySet()) {
public Iterator<Map.Entry<K, V>> iterator () {
return // some custom implementation
}
};
}
// similar for keySet() if you wish
}