Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 283|回复: 0

[默认分类] 【集合框架】Java集合框架综述

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2018-5-15 15:38:42 | 显示全部楼层 |阅读模式
    一、前言  现笔者打算做关于java集合框架的教程,具体是打算分析Java源码,因为平时在写程序的过程中用Java集合特别频繁,但是对于里面一些具体的原理还没有进行很好的梳理,所以拟从源码的角度去熟悉梳理具体类的原理和其中的数据结构。分析源码的好处总结如下三条:  1. 提升自身代码水平及写代码能力。  2. 可以顺带温习数据结构知识点。  3. 以后写代码遇到问题时能够找到最佳的解决办法二、集合框架图  做一件事情时,首先一定要有做事情的总体方法,然后再去抠细节。我们肯定要来看看集合的总体框架图,也好对集合框架有一个很感性的认识。下图展示了Java整个集合框架(没有包括并发),如果不出意外的话,以后也会出并发方面的专题分析,我们从表及里,由浅入深,慢慢来。    说明:对于以上的框架图有如下几点说明  1. 集合接口:6个接口(短虚线表示),表示不同集合类型,是集合框架的基础。
      2. 抽象类:5个抽象类(长虚线表示),对集合接口的部分实现。可扩展为自定义集合类。
      3. 实现类:8个实现类(实线表示),对接口的具体实现。
      4. Collection 接口是一组允许重复的对象。
      5. Set 接口继承 Collection,集合元素不重复。
      6. List 接口继承 Collection,允许重复,维护元素插入顺序。
      7. Map接口是键-值对象,与Collection接口没有什么关系。三、接口说明  3.1. Collection接口  除了Map接口,其他集合都是Collection的子类,并且在我们的实际编程中,由于多态的原因,我们一般都会使用这个的编码方式,如:Inter i1 = new ImplementInter();(其中,Inter表示一个接口,ImplementInter表示对此接口的实现),此时i1调用的方法只能是Inter接口中的方法,无法调用ImplementInter中新增的方法(除非进行向下类型转化)。所以,很有必要了解一下Collection根接口中都有哪些方法。
    1. public interface Collection<E> extends Iterable<E> {
    2.     int size();
    3.     boolean isEmpty();
    4.     boolean contains(Object o);
    5.     Iterator<E> iterator();
    6.     Object[] toArray();
    7.     <T> T[] toArray(T[] a);
    8.     boolean add(E e);
    9.     boolean remove(Object o);
    10.     boolean containsAll(Collection<?> c);
    11.     boolean addAll(Collection<? extends E> c);
    12.     boolean removeAll(Collection<?> c);
    13.     boolean retainAll(Collection<?> c);
    14.     void clear();
    15.     boolean equals(Object o);
    16.     int hashCode();
    17.     // jdk1.8添加的方法
    18.     default boolean removeIf(Predicate<? super E> filter) {
    19.         Objects.requireNonNull(filter);
    20.         boolean removed = false;
    21.         final Iterator<E> each = iterator();
    22.         while (each.hasNext()) {
    23.             if (filter.test(each.next())) {
    24.                 each.remove();
    25.                 removed = true;
    26.             }
    27.         }
    28.         return removed;
    29.     }
    30.     @Override
    31.     default Spliterator<E> spliterator() {
    32.         return Spliterators.spliterator(this, 0);
    33.     }
    34.     default Stream<E> stream() {
    35.         return StreamSupport.stream(spliterator(), false);
    36.     }
    37.     default Stream<E> parallelStream() {
    38.         return StreamSupport.stream(spliterator(), true);
    39.     }
    40. }
    复制代码
    View Code说明:  1. 其中在jdk1.8后添加的方法对我们的分析不会产生影响,添加的方法有关键字default修饰,为缺省方法,是一个新特性。  2. 对集合而言,都会包含添加、删除、判断、清空、大小等基本操作。  3.2. Map接口  对于Map接口而言,是键值对集合,特别适用于那种情形,一个主属性,另外一个副属性(如:姓名,性别;leesf,男),添加元素时,若存在相同的键,则会用新值代替旧值。方法如下 
    1. public interface Map<K,V> {
    2.     int size();
    3.     boolean isEmpty();
    4.     boolean containsKey(Object key);
    5.     boolean containsValue(Object value);
    6.     V get(Object key);
    7.     V put(K key, V value);
    8.     V remove(Object key);
    9.     void putAll(Map<? extends K, ? extends V> m);
    10.     void clear();
    11.     Set<K> keySet();
    12.     Collection<V> values();
    13.     Set<Map.Entry<K, V>> entrySet();
    14.     interface Entry<K,V> {
    15.         K getKey();
    16.         V getValue();
    17.         V setValue(V value);
    18.         boolean equals(Object o);
    19.         int hashCode();
    20.    
    21.         // jdk1.8 后添加的方法
    22.         public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
    23.             return (Comparator<Map.Entry<K, V>> & Serializable)
    24.                 (c1, c2) -> c1.getKey().compareTo(c2.getKey());
    25.         }
    26.         public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
    27.             return (Comparator<Map.Entry<K, V>> & Serializable)
    28.                 (c1, c2) -> c1.getValue().compareTo(c2.getValue());
    29.         }
    30.         public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
    31.             Objects.requireNonNull(cmp);
    32.             return (Comparator<Map.Entry<K, V>> & Serializable)
    33.                 (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
    34.         }
    35.         public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
    36.             Objects.requireNonNull(cmp);
    37.             return (Comparator<Map.Entry<K, V>> & Serializable)
    38.                 (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
    39.         }
    40.     }
    41.     boolean equals(Object o);
    42.     int hashCode();
    43.     default V getOrDefault(Object key, V defaultValue) {
    44.         V v;
    45.         return (((v = get(key)) != null) || containsKey(key))? v: defaultValue;
    46.     }
    47.    
    48.     default void forEach(BiConsumer<? super K, ? super V> action) {
    49.         Objects.requireNonNull(action);
    50.         for (Map.Entry<K, V> entry : entrySet()) {
    51.             K k;
    52.             V v;
    53.             try {
    54.                 k = entry.getKey();
    55.                 v = entry.getValue();
    56.             } catch(IllegalStateException ise) {
    57.                 // this usually means the entry is no longer in the map.
    58.                 throw new ConcurrentModificationException(ise);
    59.             }
    60.             action.accept(k, v);
    61.         }
    62.     }
    63.     default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
    64.         Objects.requireNonNull(function);
    65.         for (Map.Entry<K, V> entry : entrySet()) {
    66.             K k;
    67.             V v;
    68.             try {
    69.                 k = entry.getKey();
    70.                 v = entry.getValue();
    71.             } catch(IllegalStateException ise) {
    72.                 // this usually means the entry is no longer in the map.
    73.                 throw new ConcurrentModificationException(ise);
    74.             }
    75.             // ise thrown from function is not a cme.
    76.             v = function.apply(k, v);
    77.             try {
    78.                 entry.setValue(v);
    79.             } catch(IllegalStateException ise) {
    80.                 // this usually means the entry is no longer in the map.
    81.                 throw new ConcurrentModificationException(ise);
    82.             }
    83.         }
    84.     }
    85.     default V putIfAbsent(K key, V value) {
    86.         V v = get(key);
    87.         if (v == null) {
    88.             v = put(key, value);
    89.         }
    90.         return v;
    91.     }
    92.     default boolean remove(Object key, Object value) {
    93.         Object curValue = get(key);
    94.         if (!Objects.equals(curValue, value) ||
    95.             (curValue == null && !containsKey(key))) {
    96.             return false;
    97.         }
    98.         remove(key);
    99.         return true;
    100.     }
    101.     default boolean replace(K key, V oldValue, V newValue) {
    102.         Object curValue = get(key);
    103.         if (!Objects.equals(curValue, oldValue) ||
    104.             (curValue == null && !containsKey(key))) {
    105.             return false;
    106.         }
    107.         put(key, newValue);
    108.         return true;
    109.     }
    110.     default V replace(K key, V value) {
    111.         V curValue;
    112.         if (((curValue = get(key)) != null) || containsKey(key)) {
    113.             curValue = put(key, value);
    114.         }
    115.         return curValue;
    116.     }
    117.     default V computeIfAbsent(K key,
    118.             Function<? super K, ? extends V> mappingFunction) {
    119.         Objects.requireNonNull(mappingFunction);
    120.         V v;
    121.         if ((v = get(key)) == null) {
    122.             V newValue;
    123.             if ((newValue = mappingFunction.apply(key)) != null) {
    124.                 put(key, newValue);
    125.                 return newValue;
    126.             }
    127.         }
    128.         return v;
    129.     }
    130.     default V computeIfPresent(K key,
    131.             BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    132.         Objects.requireNonNull(remappingFunction);
    133.         V oldValue;
    134.         if ((oldValue = get(key)) != null) {
    135.             V newValue = remappingFunction.apply(key, oldValue);
    136.             if (newValue != null) {
    137.                 put(key, newValue);
    138.                 return newValue;
    139.             } else {
    140.                 remove(key);
    141.                 return null;
    142.             }
    143.         } else {
    144.             return null;
    145.         }
    146.     }
    147.     default V compute(K key,
    148.             BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    149.         Objects.requireNonNull(remappingFunction);
    150.         V oldValue = get(key);
    151.         V newValue = remappingFunction.apply(key, oldValue);
    152.         if (newValue == null) {
    153.             // delete mapping
    154.             if (oldValue != null || containsKey(key)) {
    155.                 // something to remove
    156.                 remove(key);
    157.                 return null;
    158.             } else {
    159.                 // nothing to do. Leave things as they were.
    160.                 return null;
    161.             }
    162.         } else {
    163.             // add or replace old mapping
    164.             put(key, newValue);
    165.             return newValue;
    166.         }
    167.     }
    168.     default V merge(K key, V value,
    169.             BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
    170.         Objects.requireNonNull(remappingFunction);
    171.         Objects.requireNonNull(value);
    172.         V oldValue = get(key);
    173.         V newValue = (oldValue == null) ? value :
    174.                    remappingFunction.apply(oldValue, value);
    175.         if(newValue == null) {
    176.             remove(key);
    177.         } else {
    178.             put(key, newValue);
    179.         }
    180.         return newValue;
    181.     }
    182. }
    复制代码
    View Code说明:  1. Map接口有一个内部接口Entry,对集合中的元素定义了一组通用的操作,维护这键值对,可以对键值对进行相应的操作,通过Map接口的entrySet可以返回集合对象的视图集,方便对集合对象进行遍历等操作。  2. 对Map而言,也会包含添加、删除、判断、清空、大小等基本操作。  3.3. Comparable接口 && Comparator接口  此接口的作用是对集合中的元素进行排序,如Integer类型默认实现了Comparable<Integer>,String类型默认实现了Comprable<String>接口,Integer与String实现了这个接口有什么作用呢?就是当集合中的元素类型为Integer或者是String类型时,我们可以直接进行排序,就可以返回自然排序后的集合。  对于Comparable接口而言,只有一个方法。 
    1. public interface Comparable<T> {
    2.     public int compareTo(T o);
    3. }
    复制代码
    View Code  我们在compareTo方法中实现我们的逻辑,就可以实现各种各样的排序。  对于Comparator接口而言,比Comparable接口类似,用作排序元素,主要的方法如下
    1. public interface Comparator<T> {
    2.     int compare(T o1, T o2);
    3.     boolean equals(Object obj);
    4.    
    5.     // jdk1.8 后的方法
    6.     default Comparator<T> reversed() {
    7.         return Collections.reverseOrder(this);
    8.     }
    9.     default Comparator<T> thenComparing(Comparator<? super T> other) {
    10.         Objects.requireNonNull(other);
    11.         return (Comparator<T> & Serializable) (c1, c2) -> {
    12.             int res = compare(c1, c2);
    13.             return (res != 0) ? res : other.compare(c1, c2);
    14.         };
    15.     }
    16.     default <U> Comparator<T> thenComparing(
    17.             Function<? super T, ? extends U> keyExtractor,
    18.             Comparator<? super U> keyComparator)
    19.     {
    20.         return thenComparing(comparing(keyExtractor, keyComparator));
    21.     }
    22.     default <U extends Comparable<? super U>> Comparator<T> thenComparing(
    23.             Function<? super T, ? extends U> keyExtractor)
    24.     {
    25.         return thenComparing(comparing(keyExtractor));
    26.     }
    27.     default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
    28.         return thenComparing(comparingInt(keyExtractor));
    29.     }
    30.     default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
    31.         return thenComparing(comparingLong(keyExtractor));
    32.     }
    33.     default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
    34.         return thenComparing(comparingDouble(keyExtractor));
    35.     }
    36.     public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
    37.         return Collections.reverseOrder();
    38.     }
    39.     @SuppressWarnings("unchecked")
    40.     public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
    41.         return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
    42.     }
    43.     public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
    44.         return new Comparators.NullComparator<>(true, comparator);
    45.     }
    46.     public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
    47.         return new Comparators.NullComparator<>(false, comparator);
    48.     }
    49.     public static <T, U> Comparator<T> comparing(
    50.             Function<? super T, ? extends U> keyExtractor,
    51.             Comparator<? super U> keyComparator)
    52.     {
    53.         Objects.requireNonNull(keyExtractor);
    54.         Objects.requireNonNull(keyComparator);
    55.         return (Comparator<T> & Serializable)
    56.             (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
    57.                                               keyExtractor.apply(c2));
    58.     }
    59.     public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
    60.             Function<? super T, ? extends U> keyExtractor)
    61.     {
    62.         Objects.requireNonNull(keyExtractor);
    63.         return (Comparator<T> & Serializable)
    64.             (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    65.     }
    66.     public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
    67.         Objects.requireNonNull(keyExtractor);
    68.         return (Comparator<T> & Serializable)
    69.             (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
    70.     }
    71.     public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
    72.         Objects.requireNonNull(keyExtractor);
    73.         return (Comparator<T> & Serializable)
    74.             (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
    75.     }
    76.     public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
    77.         Objects.requireNonNull(keyExtractor);
    78.         return (Comparator<T> & Serializable)
    79.             (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
    80.     }
    81. }
    复制代码
    View Code  我们在compare方法实现我们的比较逻辑,就可以实现各种各样的排序。四、工具类Collections && Arrays  Collections与Arrays工具类提供了很多操作集合的方法,具体的我们可以去查看API,总有一款你想要的。五、equals && hashCode  equals方法与hashCode方法在集合中显得尤为重要,所以,在这里我们也好好的理解一下,为后边的分析打下好的基础。 在每一个覆盖了equals方法的类中,也必须覆盖hashCode方法,因为这样会才能使得基于散列的集合正常运作。
      Object规范规定:  1. 在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次hashCode方法都必须始终如一的返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。
      2. 如果两个对象根据equals方法比较是相等的,那么调用者两个对象中的任意一个对象的hashCode方法都必须产生同样的整数结果。
      3. 如果两个对象根据equals方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定产生不同的整数结果。
      相等的对象必须拥有相等的散列码。即equals相等,则hashcode相等,equals不相等,则hashcode不一定相等。一个好的hashCode函数倾向于为不相等的对象产生不相等的散列码,从而提升性能,不好的hashCode函数会让散列表退化成链表,性能急剧下降。
    六、总结  集合的开篇之作就到这里了,之后会不定期的进行更新,尽请期待,谢谢各位园友观看~   
      
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-26 21:46 , Processed in 0.505467 second(s), 46 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表