《java集合》--EnumMap

《java集合》–EnumMap

说明:此文章基于jdk1.8

参考:

简介

首先对比HashMap的实现,HashMap数据结构是数组散列,key值做hash运算后根据算法落在数组上,不同的hash值最后可能落在同一个桶上,在一个桶上的多个entry对象使用链表存储,当数组没有链表存在时,HashMap性能最好为O(1)。而最差为O(threshould)即所有元素存在一个链表上

当枚举作为key存入map的情况,由于枚举值得个数是一定得,那么直接创建一个枚举值个数大小的数组用于存储,Enum性能为O(1)

所有的枚举类都继承自java.lang.Enum,根据ordinal()方法获取枚举实例的序号,然后去values数组中操作该下标处的value。

数据结构

EnumMap的存储结构是一个数组,数组中存储了value值,长度等于枚举实例的个数,根据枚举实例在枚举类中的ordinal去操作数组对应下标的value值

image

基本属性

  • private final Class keyType;// 枚举类型
  • private transient K[] keyUniverse; //枚举类型的values
  • private transient Object[] vals; //EnumMap中存放的value值

构造器

创建EnumMap时传入Enum枚举的具体类型,EnumMap会根据枚举的values的size创建一个size大小的数组

public EnumMap(Class<K> keyType) {
  this.keyType = keyType;
  //获取枚举类型的所有value
  keyUniverse = getKeyUniverse(keyType);
  //根据values的size创建数组
  vals = new Object[keyUniverse.length];
}
public EnumMap(EnumMap1<K, ? extends V> m) {
  keyType = m.keyType;
  keyUniverse = m.keyUniverse;
  vals = m.vals.clone();
  size = m.size;
}
public EnumMap(Map<K, ? extends V> m) {
  if (m instanceof EnumMap1) {
    EnumMap1<K, ? extends V> em = (EnumMap1<K, ? extends V>) m;
    keyType = em.keyType;
    keyUniverse = em.keyUniverse;
    vals = em.vals.clone();
    size = em.size;
  } else {
    if (m.isEmpty())
      throw new IllegalArgumentException("Specified map is empty");
    keyType = m.keySet().iterator().next().getDeclaringClass();
    keyUniverse = getKeyUniverse(keyType);
    vals = new Object[keyUniverse.length];
    putAll(m);
  }
}

添加元素

根据key值获取枚举的ordinal下标,直接向数组位置添加value

public V put(K key, V value) {
  //验证枚举类型是否合法
  typeCheck(key);
  //获取枚举值在枚举类中的下标
  int index = key.ordinal();
  //从数组中获取对应下标的值
  Object oldValue = vals[index];
  //数组下标处赋值
  vals[index] = maskNull(value);
  //如果第一次加入 size+1
  if (oldValue == null)
    size++;
  return unmaskNull(oldValue);
}
private void typeCheck(K key) {
  Class<?> keyClass = key.getClass();
  if (keyClass != keyType && keyClass.getSuperclass() != keyType)
    throw new ClassCastException(keyClass + " != " + keyType);
}
//处理空值
private Object maskNull(Object value) {
  return (value == null ? NULL : value);
}
//处理空值
private V unmaskNull(Object value) {
  return (V)(value == NULL ? null : value);
}
//put的时候直接根据key获取ordinal,然后修改数组该下标处的值
public V put(K key, V value) {
  typeCheck(key);
  int index = key.ordinal();
  Object oldValue = vals[index];
  vals[index] = maskNull(value);
  if (oldValue == null)
    size++;
  return unmaskNull(oldValue);
}

删除元素

获取到key值得下标,然后操作数组处指向null

public V remove(Object key) {
  if (!isValidKey(key))
    return null;
  int index = ((Enum<?>)key).ordinal();
  Object oldValue = vals[index];
  vals[index] = null;
  if (oldValue != null)
    size--;
  return unmaskNull(oldValue);
}
public void clear() {
  Arrays.fill(vals, null);
  size = 0;
}

获取元素

直接根据枚举值在枚举中的下标从value数组中获取,ordinal

public V get(Object key) {
  return (isValidKey(key) ?
          unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
}
//验证key值是否合法
private boolean isValidKey(Object key) {
  if (key == null)
    return false;

  // Cheaper than instanceof Enum followed by getDeclaringClass
  Class<?> keyClass = key.getClass();
  return keyClass == keyType || keyClass.getSuperclass() == keyType;
}

遍历

只需要遍历数组,O(n)级别

//遍历value
public boolean containsValue(Object value) {
  value = maskNull(value);
  for (Object val : vals)
    if (value.equals(val))
      return true;

  return false;
}
//遍历key 
public boolean containsKey(Object key) {
  return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null;
}
//迭代器
private abstract class EnumMapIterator<T> implements Iterator<T> {
        // Lower bound on index of next element to return
        int index = 0;

        // Index of last returned element, or -1 if none
        int lastReturnedIndex = -1;

        public boolean hasNext() {
            while (index < vals.length && vals[index] == null)
                index++;
            return index != vals.length;
        }

        public void remove() {
            checkLastReturnedIndex();

            if (vals[lastReturnedIndex] != null) {
                vals[lastReturnedIndex] = null;
                size--;
            }
            lastReturnedIndex = -1;
        }

        private void checkLastReturnedIndex() {
            if (lastReturnedIndex < 0)
                throw new IllegalStateException();
        }
    }

    private class KeyIterator extends EnumMapIterator<K> {
        public K next() {
            if (!hasNext())
                throw new NoSuchElementException();
            lastReturnedIndex = index++;
            return keyUniverse[lastReturnedIndex];
        }
    }

    private class ValueIterator extends EnumMapIterator<V> {
        public V next() {
            if (!hasNext())
                throw new NoSuchElementException();
            lastReturnedIndex = index++;
            return unmaskNull(vals[lastReturnedIndex]);
        }
    }

    private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {
        private Entry lastReturnedEntry;

        public Map.Entry<K,V> next() {
            if (!hasNext())
                throw new NoSuchElementException();
            lastReturnedEntry = new Entry(index++);
            return lastReturnedEntry;
        }

        public void remove() {
            lastReturnedIndex =
                ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
            super.remove();
            lastReturnedEntry.index = lastReturnedIndex;
            lastReturnedEntry = null;
        }

        private class Entry implements Map.Entry<K,V> {
            private int index;

            private Entry(int index) {
                this.index = index;
            }

            public K getKey() {
                checkIndexForEntryUse();
                return keyUniverse[index];
            }

            public V getValue() {
                checkIndexForEntryUse();
                return unmaskNull(vals[index]);
            }

            public V setValue(V value) {
                checkIndexForEntryUse();
                V oldValue = unmaskNull(vals[index]);
                vals[index] = maskNull(value);
                return oldValue;
            }

            public boolean equals(Object o) {
                if (index < 0)
                    return o == this;

                if (!(o instanceof Map.Entry))
                    return false;

                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                V ourValue = unmaskNull(vals[index]);
                Object hisValue = e.getValue();
                return (e.getKey() == keyUniverse[index] &&
                        (ourValue == hisValue ||
                         (ourValue != null && ourValue.equals(hisValue))));
            }

            public int hashCode() {
                if (index < 0)
                    return super.hashCode();

                return entryHashCode(index);
            }

            public String toString() {
                if (index < 0)
                    return super.toString();

                return keyUniverse[index] + "="
                    + unmaskNull(vals[index]);
            }

            private void checkIndexForEntryUse() {
                if (index < 0)
                    throw new IllegalStateException("Entry was removed");
            }
        }
    }

总结

  • 当key值是枚举类型的时候,使用EnumMap存储,会提高性能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值