“java.util.Collection” 读后感

编程入门 行业动态 更新时间:2024-10-08 00:26:42

“java.util.Collection” <a href=https://www.elefans.com/category/jswz/34/1762806.html style=读后感"/>

“java.util.Collection” 读后感

“java.util.Collection” 读后感

  • 什么是Collection接口
    • 规定实现子类的特性
    • 构造方法
    • 默认方法
    • 抽象方法
    • 提问

文中没有对每个方法涉及到的其他外部接口内容进行细究,主要是针对Collection接口的一个读后感,若读者遇到不明所以之处,不必细细追究,只用知道大致干嘛的即可,即不妨碍理解接口即可

什么是Collection接口

  • 是一个集合类的顶层接口,JDK规定了该接口不可以被直接实现,只能实现其子接口,即所有的集合类都会间接的实现该接口内的方法。
  • 该接口继承了Iterable接口。其内给定了15个抽象方法,和四个默认方法(接口内准许使用default关键字对方法进行声明,从而使得接口内也能存在具体实现的方法)。使用自然语言对描述了每个抽象的方法的期望功能,即若你要实现这个接口,那这些个抽象方法分别要做的事情是什么。这种口头的约束,并没有强有力的监督、纠错能力,只能是期望你有一定的职业操守,自动遵守大家都默认遵守的规则。

规定实现子类的特性

特性的具体实现子类,若不清楚,可以暂且不去细细追究,目前先大致了解Collection接口对于集合类的一些潜规定,并且记住就可以了

  • 有序无序。子类对存储的元素的顺序一般有两种处理方式:
    1. 依据元素放入的顺序进行存储。
    2. 依据子类内部的排序规则进行排序后存储。
  • 是否重复。即子类存储的元素是否可以重复,关键在于待存储的元素在存储之前,是否需要用hash函数处理一下:
    1. 对于List一类来说,以底层是数组的ArrayList为例,存储元素直接放入数组内部,若对位置有要求,就先算一下要存放的位置。
      到这里,其实思想本质和hash函数的处理是一样的,但是具体的实现不一样,而针对这个特点的划分也仅仅是基于实现上的区别
    2. 对于Set、Map这一类来说,以底层是数组为例,与上述上述进行比较(上述的一类存储之前是否需要计算存储位置,这个是可选的),这一类存储之前必须要进行存储位置的计算,即必须经过hash函数的处理得到一个存储位置,而计算、处理的依据是元素本身的信息(一般都是通过元素本身在ASCII或者unicode上对应的数值作为计算条件)和某一个质数(一般是31)做运算,可能还会做一个加减个位数的调整。当数据重复的时候,要求hash函数的计算结果是一样的,当一个数据是待存储的,会先进行hash函数的计算,得到存储位置,依据该位置是否有人来判断数据是否已经存在这个集合中(这里还涉及到一个hash冲突,暂不做解释,本文只是叙述一下笔者对Collection的读后感)。

笔者将collection接口中的方法分为三个大类,依据是构造方法(虽然接口没有构造方法,但是Collection接口对其实现子类的构造方法做了一些口头的约束)还是默认的实现方法亦或是抽象类型的方法,又针对抽象方法依据增删改查进行划分。(因为集合类如Collection接口、Set一类、List一类、Map一类都是用作存储数据的,其他的如迭代、排序功能,都尽量用工具类进行隔离、封装,如Collections、Arrays等工具类)

构造方法

接口没有构造方法,只是这里对其实现子类(包括直接和间接的实现子类)进行口头建议
Collection接口建议,所有它的子接口的具体实现类,在构造函数上,建议明文特别声明以下两种构造函数:

  • 无参构造函数。(会基本java语法的,都懂)
  • 类型是Collection泛型类型的形参。

默认方法

重申一下,接口内有一个default关键字,被该关键字申明的方法,可以在接口内具体实现

  1. 该方法的作用是移除 this 集合内,和 filter 集合的并集元素。
    不用管Predicate是函数式接口,不用具体理解,只用知道是一层包装
default boolean removeIf(Predicate<? super E> filter) {Objects.requireNonNull(filter);  //判断filter是否为空,为空会向调用该方法的地方抛出空指针异常(NullPointerException)boolean removed = false;final Iterator<E> each = iterator();   //获取调用方法的集合类的迭代器while (each.hasNext()) {//判断是否存在下一个值if (filter.test(each.next())) {    //test() 方法做具体的比较each.remove();  //移除当前元素removed = true;}}return removed;
}
  1. 笔者暂时也没用过,目前已知功能是做分割,将集合元素均分给其他集合。(如有不对,欢迎指正,给出理由)
 @Overridedefault Spliterator<E> spliterator() {return Spliterators.spliterator(this, 0); }
  1. (不懂之处,暂且保留,后续更新)
default Stream<E> stream() {return StreamSupport.stream(spliterator(), false);
}
  1. (不懂之处,暂且保留,后续更新)
default Stream<E> parallelStream() {return StreamSupport.stream(spliterator(), true);
}

抽象方法

    1. 添加指定的单个元素。
      boolean add(E e);
      
    2. 调用该方法将集合 c 添加到自己内部。
      boolean addAll(Collection<? extends E> c);
      
    1. 移除集合中指定的元素 o,如果元素存在,则移除,返回true,若不存在,则返回false。
      boolean remove(Object o);
      
    2. 清除集合内部全部内容。
      void clear();
      
    1. 移除与指定集合的交集元素,一般是删去部分元素,对集合做更改。若this集合是集合 c 的子集,则起到和 clean() 同样的效果。
      boolean removeAll(Collection<?> c);
      
    2. 该方法应该要实现求 this 集合和 c 集合的并集,并用并集替换 this 集和原本的元素。
      boolean retainAll(Collection<?> c);
      
    1. 查询集合中的元素个数。
      int size();
      
    2. 检查集合是否为空。若为空返回 true,若不为空返回false。
      boolean isEmpty();
      
    3. 检查集合是否包含指定的对象元素。若存在则返回true,不存在返回false。底层实现是循环遍历,比hash函数直接计算出位置慢多了,时间复杂度分别是 O(n) 和 O(1)。
      boolean contains(Object o);
      
    4. 检查集合是否包含指定集合的元素对象,类似方法retainAll()求并集,但不修改自身或者传入集合,只是确认两者是否有交集。返回布尔类型的值。
      boolean containsAll(Collection<?> c);
      
    5. 将集合内的元素转换成Object类型的数组,
      Object[] toArray();
      
    6. 将集合内的元素转换成指定类型的数组。
      <T> T[] toArray(T[] a);
      
    7. 迭代器。这是一个外部接口,被写入 Iterable 接口中,而Collection接口继承了 Iterable 接口,因此也可以使用 Iterator 接口。
      Iterator<E> iterator();
      
    8. 该方法应该判断 this 集合和 o 对象是否相等。
      boolean equals(Object o);
      
      为什么集合的equals() 方法的形参是Object类型的,不应该是 Collection 的吗?
      笔者做个Debug,this集合是一个ArrayList类型集合,调用该方法分别传入ArrayList类型变量,String类型变量,HashSet类型变量。都存入相同的值 abc 。
      传入ArrayList类型变量进行比较,结果是true,调用的是AbstractList类的equals() ,形参 o 是ArrayList类型的变量。
      传入String类型变量进行比较,结果是false,调用的是AbstractList类的equals(),形参 o是一个char[ ] 类型的变量(String底层是一个final的char[ ])。
      传入HashSet类型的变量进行比较,结果是false,调用的是AbstractList类的equals(),形参 o 是HashSet类型的变量。
      用例代码如下:
      public class test1 {public static void main(String[] args) {ArrayList<String> arrayList1 = new ArrayList<>();ArrayList<String> arrayList2 = new ArrayList<>();Set<String> set = new HashSet<>();String str = "abc";arrayList1.add("abc");arrayList2.add("abc");set.add("abc");System.out.println(arrayList1.equals(arrayList2));  //trueSystem.out.println(arrayList1.equals(str));              //falseSystem.out.println(arrayList1.equals(set));             //false}
      }
      
    9. 该方法的顶层抽象是用来计算一个变量或者对象的hash值,默认调用的hash函数是一个非java程序的本地的计算函数方法,并且可以被重写。
      该方法和equals() 都可以用作判断两个变量或者两个对象是否相等,但有一个优先级,即hashcode高于equals方法。判断逻辑如下:
      两个变量或者对象通过该方法得到属于自己的hash(理论上每个变量或对象的hash值是唯一的),如果hash值相同,表明两个变量或者对象一定是相同,即使通过equals() 函数判断两者不同,但最终结果也是两者相同,因为两者的hash值是一样的。
      如果两个不同对象计算出了相同的hash值,这种情况是hash冲突,是需要解决的问题,通常来自于hash函数不够完美。理论上hash函数能对一切进行计算,并且对每个变量或者对象计算出唯一的hash值,只有两者相同的情况下才能得到相同的hash值
      若两个变量或者对象通过equals() 判断相同,但是通过hashCode() 函数得到了不同的hash值,那么也是说明两者是不同的。
      不过一般来说,equals() 都会向 hashCode() 协同(或者叫匹配,即结果尽量是前者依赖后者)。即对equals() 进行重写的时候,会同时对配套的hashCode() 进行重写。
      int hashCode();
      

提问

  1. Collection接口实现子类的具体分类有哪些?(本文未作具体详细总结、解释,大致提到了一点内容,这里建议自己进行总结划分)
  2. Collection接口的特性中,是否重复这一特性里面,Set、Map这一类集合,为何一定要在存储之前使用hash函数进行处理 ?
  3. 理论上完美的hashCode() 是什么?
  4. 什么是hash冲突?如何避免hash冲突?

文中内容只是笔者自己的心得体会,供大家以作讨论,顶多是一个参考,谈不上解读,若有错误之处,敬请斧正。

更多推荐

“java.util.Collection” 读后感

本文发布于:2024-03-14 00:32:46,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1735228.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:读后感   java   util   Collection

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!