集合常见知识总结

集合知识总结:


  首先要明确为什么引进了集合这个概念。相对于数组来说,集合有什么不同或相同。数组是用来存储数据的,并且是同一类型的数据,且定义好了之后长度就固定了,每个元素都可以通过索引来查找,带来了许多方便。但是有时候我们存数据时,就没有那么多顾虑就会存储一些很杂并非一类型的数据,并且要存储多少我们事先也不能确定,那这时候数组就不能满足我们的使用了。所以就有集合的存在。可以知道集合能存各种类型,任意长度。接下来就纤细了解一下集合:

  集合中也分了几种情况:元素能否重复、是否允许为空、是否有序。当然重复与否的话就用equals方法来比较,区别于‘==’比较地址的方式。鉴于这种情况下就将集合分为(三个核心接口):

  1. Set集合:无序,不重复。
  2. List集合:有序,可重复。
  3. Map集合:键值对的方式,键唯一,值可重复。

在Set、List集合之上,定义接口Collection,用于定义存取Set和List类型容器中的对象的一些通用的操作。比如:增加、删除、遍历等。


一、List集合:

  继承接口Collection接口,有序、支持重复元素、允许为null、可通过索引访问元素。最常用的实现类就是ArrayList和LikedList为最常见两种。

  • ArrayList在概念上与数组相似,表示一组编入索引的元素,区别在于ArrayList没有预定的长度大小,其长度可按需要增加。其中有一些最常见的方法比如:
  1. add(index,Object o)在列表指定的位置插入对象
  2. get(int index)返回列表中指定位置的对象
  3. set(index,Object o)用指定对象去替换列表中指定位置的对象
  4. remove(int index)删除列表中指定位置的对象等等

  这里引入了一个新的概念:泛型。意思就是,我们知道集合是包含所有类型的,那么我们就像它只存一种类型这时怎么办?那么就用泛型来约束他。那为什么集合是存的所有类型对象呢?原因是:当我们把对象放入集合中的时候,集合瞬间就会高冷的忘了你是哪种类型了,当你去取的时候他就会为你把该对象编译成object类型了(当然运行时是没有变化的)。那为什么集合会这样高冷健忘呢?是因为:Java程序员在设计时他不知道你会用来存什么数据,所以就为了通用性,就设计成object类型了,可以保存任何对象。

  另外泛型也是为了解决当你从集合中取出来后要进行强转的麻烦事。用了泛型约束了它,取出来也就不需要强转了。怎么感觉没有泛型的集合也是“无状态的了”。泛型使用方式如:

  public interface Colletion<E> extends Iterractor<E>;

  public interface Set<E> extends Colletion<E>;

  public interface List<E> extends Colletion<E>;

  其中E就是你要输入的类型。这就是泛型的使用方式。

  这里还有一个值得注意的地方就是equals方法的使用,用于比较两个对象是否为相同的对象。比较的是内容。


  • LikedList:也是List接口的常见实现类,它是实现双向链表功能的列表,而且每个列表中还保存着有上一个和下一个链接的索引。其中常见的方法有:
  1. addFirst(Object o):链表开头添加一个对象。
  2. addLast(Object o):链表结尾添加一个对象。
  3. getFirst():返回第一个元素。
  4. getLast():返回最后一个元素。
  5. removeFirst():删除链表中的第一个元素。
  6. removeLast():删除链表中最后一个元素。

  LikedList和ArrayList的比较:

  1. ArrayList是采用数组的存储机制,有连续位置可以索引,那么在删除和插入操作时就非常的麻烦了。比如:你无论是删除还是插入一个元素进去,都会影响它固有的元素位置。
  2. LikedList是链表形式的,不支持快速查询,要查询的话必须是从头开始来找,异常麻烦并且很慢。但是删除插入就很快了,它不会像ArrayList那样又要排序一次。
  3. 所以,一般情况下,ArrayList用于查询,LikedList用于删除和插入。

二,Set集合:

  首先这个集合也是继承自Collection接口,同时也继承了Collection接口的全部方法。其特点如下:

  1. Set类型容器中不能包含重复元素,当你加入一个新的元素时要进行比较,用重写equals方法的方式进行比较,来判断是否是重复元素。
  2. 元素可能没有顺序,也可能有顺序。
  3. 由于可能存在没有顺序的可能,所以就不能基于索引访问Set集合中的元素。
  4. 最常用的集合是:HashSet和TreeSet两种。

1.HashSet:

  是基于哈希算法的set接口实现,有如下一些特点:

  • 当遍历HashSet集合时,其中的元素是没有顺序的。
  • 其中不允许重复元素的出现,要重写equals方法来判断是否重复。这里的重复是指相同的哈希码,并且调用equals方法比较时返回为true的两个元素对象。
  • 允许包含null元素。

上述提到遍历这个概念,那么遍历的使用形式是怎样的——用foreach循环遍历HashSet中的对象,语法格式是:for(类型:集合);

当然我们还需要明确一点的就是当在比较HashSet中元素是否为同一元素时,我们仅仅是重写equals方法是不完善的,不足以来判断两元素是否为完全相同的元素。那么我们如何完善这种比较机制呢?

  如果我们编写的类重新定义了equals方法,那么这个类也必须重新定义hashCode方法,并且保证当两个对象用equals方法比较结果为true时,这两个对象的hashCode方法的返回值为相等。

  说到这里大概还是不懂为什么就必须得重写equals和hashCode这两个方法才能来准确判断呢?

我们要理解HashSet的存储机制,在基于哈希算法的集合类(包括hashCode、HashMap、HashTable等)中,每个能储存元素的位置称为:‘桶’,一个桶中能装很多元素,而桶的位置由hashCode算法计算而来的哈希码值来决定的。不同的哈希码值的对象存放在桶不同的桶中,一个桶中的多个对象具有相同的哈希码值,因此我们重写hashCode方法只是来找到了桶的位置,调用equals方法来进行对桶中的元素判断比较,返回true才能说这两个对象是相同的对象。

  所以我们得到一个结论:当我们要将对象添加到HashSet、HashMap、Hashtable等基于哈希算法的集合类中时,必须同时重写hashCode和equals方法才能准确判断对象是否为同一对象。不同时重写两方法的话就不能准确比较。

2.TreeSet:

  TreeSet不仅实现Set集合,还实现了SortedSet接口的,从而保证了集合中的对象是按照一定的顺序来排序的。当向TreeSet集合中添加一个对象时,会把它插入到有序的对象序列中。但是这种排序并不是按照对象添加的顺序排序的,而是按照一定的算法来排序的。其中TreeSet集合中也有一些独有的方法比如:

  • first();返回TreeSet中第一个元素。
  • last();返回TreeSet集合中最后一个元素。
  • pollFirst();获取并删除第一个元素。
  • pollLast();获取并删除最后一个元素。
  • higher(Object o);返回此集合中严格大于给定元素的最小元素。集合最小的元素都要比给定的大才能满足。
  • lower(Object o);返回此集合中严格小于给定元素的最大元素。集合中最大的元素都要比给定元素小才能满足。
  • headSet(Object o);返回集合的部分视图,其元素严格小于指定元素o。
  • tailSet(Object o);返回集合的部分视图,其元素严格大于制定元素o。

那么我们得明白该集合是使用了什么方式来进行排序的?TreeSet使用元素的自然排序进行排序的,或者根据创建set时提供的Comparator进行排序,具体取决于使用的构造方法。也就是说,TreeSet支持自然排序和自定义排序两种排序方式。默认情况下TreeSet是使用自然排序方式。

  注意:这里的TreeSet不是调用它自己的comparaeTo()方法,而是调用集合中对象的comparaeTo()方法。TreeSet类本身并没有实现Comparable接口。

  1.是实现的Comparable接口来进行排序的,里面有一个comparaeTo(Object o)的方法,返回整型数据,对于x.comparaTo(y):

  1. =0,x=y。
  2. >0,x>y。
  3. <0,x<y。
  • 对于JDK常用类,例如:Double、Integer、Long、Short、Float等,是按照数字的大小排序的。
  • Character类,按照Unicode值的数字大小进行排序。
  • String对象,按照字符串中字符的Unicode值排序。
  • 注意:使用自然排序时,只能向集合中加入同类型的对象,并且这些对象的类必须实现了Comparable接口,否则程序会抛出异常。

  2.TreeSet的自定义排序是实现Comparator接口,通过调用compare(Object o1,Object o2)方法,进行两参数的比较:

  1. 返回-1则:o1<o2
  2. 返回0则:o1=o2
  3. 返回1则:o1>o2
  4. 当然我们也可以重写让它按照我们的方式排列。

( 这种比较的机制在我们实际运用中非常重要的,面试时也有许多面试官青睐与这个知识点。)


 三,Map集合:

  Map映射集合是java集合框架中,不同于Collection接口的另一个重要接口。它对应的是一种从键(Key)到值(value)的对应关系的集合。也就是说,map类型的集合对象容器中保存着两组对象,一组对象用于保存Map里的key,另外一组用于保存value。key和value可以是任何引用类型的数据。其中key不能重复,但是value可以重复。这两者存在着单向的一对一的关系,即通过key可以找到与之对应的唯一的value值。Map接口定义了Map集合所共有的方法,这些方法分为三类:基本操作、批量操作、Collection视角操作。Collection视角操作提供了将map转化为Collection的手段。

  • 基本操作:
  1. get(Object key);返回与指定键相关的值
  2. put(Object key,Object value);向该映射中添加键值对
  3. remove(Object o);从映射中删除包含指定的键的键值对
  4. containsKey(Object key);如果该映射包含key值,则返回true
  5. containsValue(Object value);如果该映射包含value值,则返回true
  6. size();返回该映射对象中包含的键值对映射关系数
  7. isEmpty();如果该映射为空,则返回为true
  • 批量操作:
  1. clear();删除映射内所有元素。
  2. putAll(Map m);将指定映射中所有映射关系复制到此映射中。
  • Colletion视角操作:
  1. keySet();返回一个包含映射中所有的Key的Set对象。
  2. values();返回一个包含映射中所有的value的Collection对象。
  3. entrySet();返回一个包含该Map中所有条目的Set对象,条目由内部接口Entry定义。

HashMap和TreeMap是常见的实现类,其中HashMap是基于哈希算法的,要保证存储的唯一性,也需要重写hashCode和equals方法来进行判断,HashMap是没有顺序的。要想有顺序就用TreeMap。TreeMap是基于红黑二叉树算法的Map接口实现,键的排序也分为自然排序和自定义排序两种。

  


四,工具类Collections和Arrays两种:

   Colletions是集合框架用来操作Set、Map、List集合的工具类,用于对集合的排序、查询、修改等操作。这些方法都是静态的直接可以调用的。由于现在的集合都是线程不安全的所以,Collections中就提供了一些方法来改变这种性质,如:

  1. synchronizedCollection(Collection c):返回一个线程安全的Collection
  2. synchronizedList(List list):返回一个线程安全的List集合,同理SetMap都是如此。

  Arrays工具类就是提供了用于操作数组的,比如排序和搜索。


 五,古老的集合类与接口:

  Vector与ArrayList的用法几乎完全相同,二者最大的区别在于Vector类是线程安全的而ArrayList是线程不安全的,所以效率上要比ArrayList要低些。如果在实际运用中如果不考虑此线程安全的问题的话,那么就选用ArrayList使用。

  Hashtable与HashMap的用法也几乎一样,二者关系如上述两者关系非常相似。还有一个不同点就是Hashtable不允许Key和value值为空,而HashMap是允许的。

  总结新老集合的性质,老的集合都是线程安全的,新的集合都是线程不安全的。那么这时候就要调用Collections中线程安全的方法来实现线程安全的机制。

  Hashtable中还有一个子类properties,也是这四个集合中到现在还被使用频繁的一个类。该类适用于处理属性文件,所谓处理属性文件就是将Map形式的键/值对数据存在一个扩展名为“Properties”的文本文件中,常用作软件的配置文件。例如jdbc.properties文件用于配置JDBC链接到MySql数据库所需的信息。

  properties类的主要方法:

  1. String getProperty(String key);根据属性的键key获取属性对应的值
  2. String getPriperty(String key,String defaultValue);根据属性的key获取属性的值,如果没有该key值,则返回默认值。
  3. Object setProperty(String key,String value);设置属性
  4. void load(InputStream in);从输出流中装载全部属性。
  5. void store(OutputStream out,String comments);降属性内容通过输出流输出。

  Enumeration接口是JDK1.0就出现的最古老的遍历器,用于遍历Vector、Stack、Hashtable、Properties等JDK1.0遗留下来的集合类,该接口只有两个方法:

  1. boolean hashMoreElement();测试集合中是否还有更多的元素。如果有返回true。
  2. Object nextElement();返回下一个元素。

  集合的知识就总结到这里了,其中总结出来的这些都是平时使用过程中应该注意个掌握的。其中古老的集合与现在的集合也是经常会被面试官喜欢问的问题,意图就是考察你是否全面的掌握集合的相关知识。还有properties类的那些方法会在配置文件时用到,就如封装JDBC时就用到了。 

   今天是进入公司的第二天,感触很多,做的项目比以往接触到的项目都要大得多数据复杂得多。同时自己感觉心里也很着急,成天坐在那里翻来覆去的看,依然没什么头绪,好不容易有点头绪了,但是还是不能做点什么,内心很焦急。想起一句话:人这一生或许要经历许多的不同以往经历的第一次。既然是没经历过的,肯定就会有挑战,有挑战才会有收获。持之以恒,静下心来,越困难就代表收获越大。以积极的态度去面对,以最适合的方法克服困难。不能浪费掉这样好的成长机会。努力、坚持......

 

原文地址:https://www.cnblogs.com/tyhJava/p/5612291.html