`

java集合----HashMap与set关系

阅读更多

曾经在做开发的过程中,编写了如下一段代码:

		map.put("dbradius","C:/temp/dbradiusx_script.xml");
		map.put("radius","C:/temp/radius_script.xml");
/*
	 * 保证脚本可用
	 */
	public boolean isUsable(){
		Iterator<String> iterator = map.keySet().iterator();
		while(iterator.hasNext()){
			String key = iterator.next();
			File f = new File(map.get(key));
			if(!f.exists()){
				MyTools.getLogger().error(" path " +map.get(key)+ " is unavaible!");
				map.remove(key);
			}
		}
		return map.size()>0?true:false;
	}

功能非常简单,就是将map中的value值所代表的非法路径(不存在的文件)移除。执行后报错,如下:

Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
	at java.util.HashMap$KeyIterator.next(HashMap.java:828)
	at com.network.manager.nmsmanager.db.util.Bootstrap.isUsable(Bootstrap.java:68)
	at com.network.manager.nmsmanager.db.util.Bootstrap.executeTasks(Bootstrap.java:82)
	at com.network.manager.nmsmanager.db.util.Bootstrap.main(Bootstrap.java:49)

出错的根本原因在于HashMap为了保证线程安全,采取了一种策略,分析完HashMap的源代码就会知道问题出在哪里了。

如上可以这样来解决,如下:

while(iterator.hasNext()){
			String key = iterator.next();
			File f = new File(map.get(key));
			if(!f.exists()){
				MyTools.getLogger().error(" path " +map.get(key)+ " is unavaible!");
				iterator.remove();// 只有在调用过next方法后才可调用iterator的remove
			}
		}

Iterator 支持从源集合中安全地删除对象,只需在 Iterator 上调用 remove() 即可。这样做的好处是可以避免 ConcurrentModifiedException ,这个异常顾名思意:当打开 Iterator 迭代集合时,同时又在对集合进行修改。有些集合不允许在迭代时删除或添加元素,但是调用Iterator  remove() 方法是个安全的做法。

通常来说,Map是一个由键值对组成的数据结构,且在集合中每个键是唯一的。下面就以K和V来代表键和值,列出一下java中关于Map的九大问题,也是面试中经常遇到的问题,如下:

  1. 将Map转换为List类型
  2. 通过Entry 遍历Map
  3. 通过Key来对Map排序
  4. 对value对Map进行排序
  5. 初始化一个static 的常量Map
  6. HashMap, TreeMap, and Hashtable之间的不同
  7. Map中的反向查询
  8. 对Map的复制
  9. 创建一个空的Map

在分析完源代码,读者可以回顾一下这几个问题。

Map<String, String[]> paraMap = new HashMap<String, String[]>();
for( Entry<String, String[]> entry : paraMap.entrySet() )
{
    String appFieldDefId = entry.getKey();
    String[] values = entry.getValue();
}

 

 

HashMap 的底层由一个散列表来实现,存储的内容是键值对(key-value),且键值不能重复,最多允许有一个null值。

 

1、Map与Set的关系

 

Set集合的特点是不能存储重复元素,不能保持元素插入时的顺序,且key值最多允许有一个null值。

由于Map中的key与Set集合特点相同,所以如果将Map中的value值当作key的附属的话,所有的key值就可以组成一个value集合

来看一下两个集合的实现类图:

 

     

                                                         Set 集合框架图 

                                                        Map集合框架图 

可以看到,两者的类图特别的相似。

 

2、Map与Set的关系

 

Map接口中定义的部分重要方法如下:

public interface Map<K,V> {

    boolean containsKey(Object key);
    boolean containsValue(Object value);

    V get(Object key);

    // Modification Operations
    V put(K key, V value);
    V remove(Object key);

    // Bulk Operations
    void putAll(Map<? extends K, ? extends V> m);
    void clear();


    // Views
    Set<K> keySet();                 // 由于Map集合的key不能重复,key之间无顺序,所以Map集合中的所有key就可以组成一个Set集合
    Collection<V> values();          // 获取所有的values集合
    Set<Map.Entry<K, V>> entrySet(); // 获取所有的key-value键值对,由Map.Entry<K,V>来表示

    interface Entry<K,V> {           // 表示key-value对实体
        K getKey();
        V getValue();
        V setValue(V value);
        // 省略部分常见方法
    }
    // 省略部分常见的方法
}

对部分方法说明一下:

  1. values() 方法 通过调用这个方法就可以返回Map集合中所有的value值;
  2. keySet()方法 调用后可以得到所有Map中的 key值,这些值可以组成一个Set集合
  3. entrySet()方法   得到所有的Map中key-value键值对,以Set集合的形式存储。将key看作Set中的元素,value当作 key的附属即可。

为了能够更好的表示这个key-value值,接口中还定义了一个Entry<K,V>接口,并且在这个接口中定义了一些操作key和value的方法。

 

3、Map中定义的变量及构造函数

 

public class HashMap<K,V>  extends AbstractMap<K,V>   implements Map<K,V>, Cloneable, Serializable{

    static final int DEFAULT_INITIAL_CAPACITY = 16; // 默认的初始化容量大小,必须是2的平方
    static final int MAXIMUM_CAPACITY = 1 << 30;    // 最大的容量

    static final float DEFAULT_LOAD_FACTOR = 0.75f; // 指定负载因子

    transient Entry[] table;   // 存储key-value对
    transient int size;        // 存储的实际key-value对数量
    int threshold;             // 所能容纳的key-value对极限
    final float loadFactor;    // 负载因子 
    transient int modCount;    // 记录修改内容的次数
}

代码中有几个变量需要说明一下:

  1. table数组用来存储key-value对,在调整数组的大小时值肯定是2的平方。
  2.  loadFactor 负载因子,增大值时可以减少Hash表(也就是Entry数组)所占用的内存空间,但会增加查询数据时时间的开销,而查询是最频繁的操作;减小值时会提高数据查询的性能,但是会增大Hash表所占用的内存空间,所以一般是默认的0.75。
  3.  threshold 表示HashMap所能容纳的key-value对极限,如果存储的size数大于了threshold,则需要扩容了,值一般为capacity*loadFactor。

HashMap提供了几个构造函数,如下:

  public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
        // Find a power of 2 >= initialCapacity
        int capacity = 1;
        while (capacity < initialCapacity)        // 计算出大于initialCapacity的最小的2的n次方值
            capacity <<= 1;
        this.loadFactor = loadFactor;
        threshold = (int)(capacity * loadFactor); // 设置容量极限
        table = new Entry[capacity];              // 将刚计算出的capacity当作Entry数组的大小
        init();
    }

    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
        table = new Entry[DEFAULT_INITIAL_CAPACITY];
        init();
    }

    public HashMap(Map<? extends K, ? extends V> m) {
        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
        putAllForCreate(m);
    }

由第一个构造函数可以看出,其实际的capacity一般是大于我们指定的initialCapacity,除非initialCapacity正好是2的n次方值。

 

4、key-value存储实体 - Entry

 

接着就来说一下HashMap的实现原理吧。首先来看一下代表key-value对的Entry实现,如下:

private static class Entry<K,V> implements Map.Entry<K,V> { // 实现Map接口中定义的Entry接口
        int hash;
        K key;
        V value;
        Entry<K,V> next;
        protected Entry(int hash, K key, V value, Entry<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
        protected Object clone() {
            return new Entry<>(hash, key, value,(next==null ? null : (Entry<K,V>) next.clone()));
        }
        public K getKey() {   // 获取key值
            return key;
        }
        public V getValue() { // 获取value值
            return value;
        }
        public V setValue(V value) { // 为value设置新的值
            if (value == null)
                throw new NullPointerException();
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }
        public boolean equals(Object o) { // 通过比较key和value值来确定两个Entry是否相等
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry e = (Map.Entry)o;
            return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
               (value==null ? e.getValue()==null : value.equals(e.getValue()));
        }
        public int hashCode() {
            return hash ^ (value==null ? 0 : value.hashCode());
        }
        public String toString() {
            return key.toString()+"="+value.toString();
        }
    }

       了解了key-value存储的基本结构后,就可以考虑如何存储的问题了。HashMap顾名思义就是使用哈希表来存储的,哈希表为解决冲突,采用了开放地址法和链地址法来解决问题。Java中HashMap采用了链地址法。链地址法,简单来说,就是数组加链表的结合。在每个数组元素上都一个链表结构,当数据被hash后,得到数组下标,把数据放在对应下标元素的链表上。

       当程序试图将多个 key-value 放入 HashMap 中时,以如下代码片段为例:

HashMap<String , Double> map = new HashMap<String , Double>(); 
map.put("语文" , 80.0); 
map.put("数学" , 89.0); 
map.put("英语" , 78.2); 

       HashMap 采用一种所谓的“Hash 算法”来决定每个元素的存储位置。

       当程序执行 map.put("语文" , 80.0); 时,系统将调用"语文"的 hashCode() 方法得到其 hashCode 值——每个 Java 对象都有 hashCode() 方法,都可通过该方法获得它的 hashCode 值。得到这个对象的 hashCode 值之后,系统会根据该 hashCode 值来决定该元素的存储位置。

对于数组类型的Key值是怎么算HashCode值呢?

 Map<String[], String> paraMap = new HashMap<String[], String>();



 

5、添加元素

 

 HashMap 类的 put(K key , V value) 方法的源代码:

/*
 *  当向HashMap中添加mapping时,由key的hashCode值决定Entry对象的存储位置,当两个 key的hashCode相同时,
 *  通过equals()方法比较,返回false产生Entry链,true时采用覆盖行为
 */
public V put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
         /*
          *  如果hash值相同且key值的索引或内容相同,则采取覆盖行为,然后返回旧值
          *  这样不会对modCount进行加1操作,也就是说这样不认为是结构发生了改变
         */
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }
    modCount++;
    addEntry(hash, key, value, i);
    return null;
} 

     当key值为空时,调用putForNullKey()方法进行值的添加,如下:

 private V putForNullKey(V value) {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(0, null, value, 0);
        return null;
    }
 void recordAccess(HashMap<K,V> m) {   }

     当系统决定存储 HashMap 中的 key-value 对时,完全没有考虑 Entry 中的 value,仅仅只是根据 key 来计算并决定每个 Entry 的存储位置。这也说明了前面的结论:我们完全可以把 Map 集合中的 value 当成 key 的附属,当系统决定了 key 的存储位置之后,value 随之保存在那里即可。     

     如果key为null,则hashCode值为0。所以需要遍历table[0]处的Entry链。如果已经存在null键,则覆盖并返回原始值。否则调用addEntry()方法进行添加。

接着看put(K key,V value)方法,有如下源代码:

        int hash = hash(key.hashCode());       // 计算hash值
        int i = indexFor(hash, table.length);  // 计算保存在table数组索引的位置

    根据 hashCode() 返回值来计算 Hash 值的方法,并且会调用 indexFor() 方法来计算该对象应该保存在 table 数组的哪个索引,源代码如下:

    static int hash(int h) {
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
    static int indexFor(int h, int length) {
        return h & (length-1);
    }

对两个方法的说明如下:       

  • length是table数组的长度,所以数组的长度总是 2 的 n 次方,通过h&(length-1)计算后,保证计算得到的索引值位于 table 数组的索引之内,计算的方法并不总是这样的,好的计算方法应该还会让索引值尽量平均分布到数组中,以减少冲突。
  • hash()方法,目前还没有理解为什么要经过这样的计算       

        当调用put()方法向 HashMap 中添加 key-value 对,由其 key 的 hashCode() 返回值决定该 key-value 对(就是Entry 对象)的存储位置。当两个 Entry 对象的 key 的 hashCode() 返回值相同时,将由 key 通过 eqauls() 比较值决定是采用覆盖行为(返回 true),还是产生 Entry 链(返回 false),而且新添加的 Entry 位于 Entry 链的头部,这是通过调用addEntry()方法来完成的,源码如下:

void addEntry(int hash, K key, V value, int bucketIndex){ 
    Entry<K,V> e = table[bucketIndex];                        // 获取指定 bucketIndex 索引处的 Entry 
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e); // 将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entry 
    // 如果 Map 中的 key-value 对的数量超过了极限
    if (size++ >= threshold) 
            resize(2 * table.length); 	                     //  把 table 对象的长度扩充到 2 倍

} 

      将新添加的 Entry 对象放入 table数组的 bucketIndex 索引处。如果 bucketIndex 索引处已经有了一个 Entry 对象,那新添加的 Entry 对象指向原有的 Entry 对象(产生一个 Entry 链),如果 bucketIndex 索引处没有 Entry 对象, e 变量是 null,也就是新放入的 Entry 对象指向 null,也就是没有产生 Entry 链。

 

5、获取元素

 

 get()方法的源代码如下:

public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        // 搜索该Entry链的下一个Entry,有多个Entry链时必须顺序遍历,降低了索引的速度
        // 如果Entry链过长,说明发生“Hash”冲突比较频繁,需要采用新的算法或增大空间
        for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { 	 
               Object k;
               if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
         }
         return null;
    }

        当 HashMap 的每个 bucket 里存储的 Entry 只是单个 Entry 时的 HashMap 具有最好的性能:当程序通过 key 取出对应 value 时,只要先计算出该 key 的 hashCode() 返回值,在根据该 hashCode 返回值找出该 key 在 table 数组中的索引,然后循环遍历查找 hash值相同,key值相同的value。

        key为空值时调用getForNullKey()方法,源代码如下:

 private V getForNullKey() {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
            if (e.key == null)
                return e.value;
        }
        return null;
    }

key为null的Entry只可能存在于索引值为0处,遍历这个链即可。

 

6、获取key集合、values集合和Entry集合

 

分别调用如下的三个方法的进行集合的获取,其中有两个定义在AbstractMap类中,如下:

transient volatile Set<K>                keySet = null;
    transient volatile Collection<V>     values = null;

下面一个为HashMap中,如下:

    private transient Set<Map.Entry<K,V>> entrySet = null;

通过如果的方法来获取集合:

public Set<K> keySet() {               // 所有的HashMap的key值放入到Set集合
    Set<K> ks = keySet;
    return (ks != null ? ks : (keySet = new KeySet()));
}
public Collection<V> values() {        // 所有的HashMap的value值放入到Collection集合
    Collection<V> vs = values;
    return (vs != null ? vs : (values = new Values())); 
}
public Set<Map.Entry<K,V>> entrySet() { // 将Entry放到Set集合中
    return entrySet0();
}

private Set<Map.Entry<K,V>> entrySet0() {
    Set<Map.Entry<K,V>> es = entrySet;
    return es != null ? es : (entrySet = new EntrySet());
}

在每次获取对应的集合时,都会进行判断。如果变量的值来为空,则直接返回即可,否则调用静态的内部类来获取。能够看出来

 

分别得获取KeySet、Values和EntrySet私有类的实例,那么他们是怎么从HashMap中取出自己需要的内容呢?其实这里会涉及到非常多的类和方法,大概框架如下所示:

 

 

 

如上类中最重要的就是HashIterator类的实现,如下:

 private abstract class HashIterator<E> implements Iterator<E> {
        Entry<K,V> next;        // next entry to return
        int expectedModCount;   // For fast-fail
        int index;              // current slot
        Entry<K,V> current;     // current entry

        HashIterator() {
            expectedModCount = modCount;
            if (size > 0) { // advance to first entry
                Entry[] t = table;
                while (index < t.length && (next = t[index++]) == null); // 将index指向第一个table不为null的位置
            }
        }
        public final boolean hasNext() {
            return next != null;
        }
        /*
         * 这个方法是final类型的,不可以被子类覆盖,只有包访问权限,所以应用程序不可以调用
         * 查找下一个Entry,下一个Entry可能与前一个Entry在不同的链表上。关于为什么这样定义还不是很清楚
         */
        final Entry<K,V> nextEntry() {      
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Entry<K,V> e = next;
            if (e == null)
                throw new NoSuchElementException();
            if ((next = e.next) == null) {   // 如果遍历完一个Entry链,则继续查找下一个Entry链的索引
                Entry[] t = table;
                while (index < t.length && (next = t[index++]) == null);
            }
            current = e;
            return e;
        }
        public void remove() {               
            if (current == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            Object k = current.key;
            current = null;
            HashMap.this.removeEntryForKey(k);
            expectedModCount = modCount;
        }

    }

和ArrayList一样,在获取到HashMap的Iterator对象后,就不可以调用HashMap中的方法添加或删除的操作了,否则会出现异常。可以使用HashIterator类进行当前的key-value对。

下面以EntrySet的实现为例,这个类是私有静态内部类,如下:

    private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
        public Iterator<Map.Entry<K,V>> iterator() {
            return newEntryIterator();
        }
        public boolean contains(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<K,V> e = (Map.Entry<K,V>) o;
            Entry<K,V> candidate = getEntry(e.getKey());
            return candidate != null && candidate.equals(e);
        }
        public boolean remove(Object o) {
            return removeMapping(o) != null;
        }
        public int size() {
            return size;
        }
        public void clear() {
            HashMap.this.clear();
        }
    }

获取到EntrySet实例后就就可以调用iterator()方法进行元素的遍历了。用的是newEntryIterator()方法,这个方法定义如下:

 Iterator<Map.Entry<K,V>> newEntryIterator()   {
        return new EntryIterator();
 }
 private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
        public Map.Entry<K,V> next() {
            return nextEntry();
        }
    }

这个方法只实现了next()方法,这个方法中调用了HashIterator类中的final方法。定义为final,可能是一种遍历原则吧。其他都是继承HashIterator类中的方法,如hashNext()等方法。下面来举一个例子:

 

HashMap map=new HashMap();
		map.put("a", "value1");
		map.put("b", "value2");
		map.put("c", "value3");
		
		Set<Map.Entry<String,String>> s=map.entrySet();
		Iterator iter=s.iterator();
		while(iter.hasNext()){
			System.out.println(iter.next());
		}

最后运行的结果如下:b=value2
c=value3
a=value1

分享到:
评论

相关推荐

    Java-Java集合体系-List-Set

    理解并熟练运用Java集合体系中的List、Set、Map接口及其实现类,对于日常开发和面试来说至关重要,因为它们是许多Java框架和库的基础。在实际项目中,根据需求选择合适的集合类型可以提高代码的效率和可维护性。在...

    精通java集合框架--List,Set..

    ### 精通Java集合框架——List, Set, Map #### 概述 Java集合框架是一种高度抽象且灵活的数据组织工具,它通过一系列接口来定义不同类型的数据容器,并提供了丰富的操作这些容器的方法。本文将深入探讨Java集合...

    大学课程讲义-Java基础-Java集合.pptx

    Java 集合类可以分为 Set、List 和 Map 三种体系,分别用于存储无序、不可重复的集合、有序、可重复的集合和具有映射关系的集合。 Collection 接口是 Java 集合框架的核心接口,定义了基本的集合操作方法,如 add...

    Java集合类List-Set-Map的区别和联系.doc

    Java 集合类 List-Set-Map 的区别和联系 Java 集合类 List、Set 和 Map 是 Java 语言中最基本的集合类,它们之间存在着紧密的联系和区别。在本文中,我们将对 Java 集合类 List、Set 和 Map 的区别和联系进行详细的...

    java基础 集合-21-对象的一对多与多对多

    在Java编程语言中,集合框架是处理对象数组的...总之,理解和熟练掌握Java集合框架中的对象关系处理是成为一名优秀Java开发者的关键技能之一。通过本课程的学习,你可以深化对这些概念的理解,提升你的编程实践能力。

    Java基础----集合类汇总

    本文将深入探讨Java集合类的汇总,包括List、Set和Map这三大核心接口及其实现类。 首先,让我们从List接口开始。List是一种有序的集合,允许有重复元素,并且支持通过索引来访问元素。ArrayList和LinkedList是List...

    java集合-HashSet的使用

    HashSet 是 Java 中的一个集合类,它实现了 Set 接口并提供了基于哈希表的无序、不重复元素的集合。具体来说,它是通过哈希表(实际上是一个 HashMap 实例)来存储元素的。 以下是 HashSet 的一些主要特点: 无序...

    java集合类详解(set list ArrayList等java集合类详述)

    Java 集合类详解 Java 集合类是 Java 语言中的一种基本数据结构,用于存储和操作大量数据。集合类可以分为三大类:Collection、List 和 Set。 Collection 是集合框架中的根接口,提供了基本的集合操作,如 add、...

    Java--collection.rar_SEP_java 集合

    Java集合框架是Java编程语言中的一个核心组件,它为数据存储和管理提供了强大的支持。这个框架包括了多种接口和类,使得程序员可以高效地处理对象集合。在"Java--collection.rar"这个压缩包中,我们可以找到名为...

    Java-Interview-超全集合github上评分最高的jiva面试题

    - **集合接口与实现**:了解Collection、Iterable、List、Set、Map等接口,以及它们各自的实现类。 3. **并发编程** - **线程**:创建线程的方式,理解线程的状态转换,掌握ThreadLocal的使用。 - **同步机制**...

    【死磕Java集合】-集合源码分析.pdf

    在Java集合框架中,LinkedList、ArrayList、HashMap、TreeMap等都是非常常用的数据结构。本文将对Java集合框架的源码进行分析,深入探讨其实现原理和机制。 一、LinkedList源码分析 LinkedList是一种以双向链表...

    Java源码分析:集合-容器.pdf

    Java集合框架是Java编程语言中非常重要的组成部分,它为Java开发者提供了大量用于存储数据的结构。Java集合框架主要包括两大类,单列集合和双列集合。单列集合中,Set接口的集合主要用于存储不重复的元素,而List...

    Java HashMap类详解

    在介绍集合存储之前需要指出一点:虽然集合号称存储的是 Java 对象,但实际上并不会真正将 Java 对象放入 Set 集合中,只是在 Set 集合中保留这些对象的引用而言。也就是说:Java 集合实际上是多个引用变量所组成的...

    Java笔记-集合与算法

    ### Java集合与算法知识点 #### 一、集合接口与实现 **Java集合框架**是Java标准库的一个核心组成部分,它提供了存储和操作集合的一系列接口和实现类。这些集合类库的设计遵循了一些基本的原则,例如将接口与实现...

    Java集合框架常见面试题.pdf

    总结来说,Java集合框架为开发者提供了丰富的数据结构以应对不同场景的需要,从简单的List和Set到复杂的Map结构,再到线程安全的集合实现,每个组件都有其特定的用途和优势。在面试中,理解并能够熟练运用这些集合类...

    Java-Java集合教程

    Java集合框架是Java编程语言中一个非常重要的组成部分,它提供了数据结构和算法的实现,使得在处理对象集合时更加高效和灵活。Java集合教程通常会涵盖以下关键知识点: 1. **集合接口**: - `Collection`:这是...

    Java 实例 - 集合输出源代码+详细指导教程.zip

    本教程的"Java实例 - 集合输出源代码+详细指导教程.zip"旨在帮助开发者深入理解Java集合框架,并通过实例源代码进行实践学习。 集合框架包括接口、类和算法,主要由以下部分组成: 1. **接口**:这些是集合的抽象...

    JAVA基础-集合类

    ### JAVA基础-集合类 #### 一、集合的概述与分类 ##### 1. 集合概述 集合是Java编程语言中一种重要的数据结构,它用于存储一系列的对象。与数组相比,集合提供了更加灵活的方式来处理数据。集合的一个显著特点是它...

    Java集合排序及java集合类详解.pdf

    Java集合框架提供了多种数据结构,包括列表(List)、集(Set)和映射(Map),这些数据结构允许程序员以高效的方式处理大量数据。 ##### 1.1 容器简介 容器是Java集合框架的基础概念,它们用于存储对象的集合。容器分为...

Global site tag (gtag.js) - Google Analytics