java集合

Posted 爽走不解释

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java集合相关的知识,希望对你有一定的参考价值。

干活有点多 ,细心阅读会有收益的

一、什么是java集合?

很难给集合下一个精确的定义,通常情况下,把具有相同性质的一类东西,汇聚成一个整体,就可以称为集合。
抽象一点来说:每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector、Stack、HashTable和Array。随着集合的广泛使用,Java1.2提出了囊括所有集合接口、实现和算法的集合框架。在保证线程安全的情况下使用泛型和并发集合类,Java已经经历了很久。它还包括在Java并发包中,阻塞接口以及它们的实现。

二、java集合类

集合类是用来存放某类对象的。集合类有一个共同特点,就是它们只容纳对象(实际上是对象名,即指向地址的指针)。这一点和数组不同,数组可以容纳对象和简单数据。如果在集合类中既想使用简单数据类型,又想利用集合类的灵活性,就可以把简单数据类型数据变成该数据类型类的对象,然后放入集合中处理,但这样执行效率会降低。

集合类是Java数据结构的实现。在编写程序时,经常需要和各种数据打交道,为了处理这些数据而选用数据结构对于程序的运行效率是非常重要的。


Java中的集合类可以分为两大类:一类是实现Collection接口;另一类是实现Map接口。
1、Collection是一个基本的集合接口,Collection中可以容纳一组集合元素(Element)。
2、Map没有继承Collection接口,与Collection是并列关系。Map提供键(key)到值(value)的映射。一个Map中不能包含相同的键,每个键只能映射一个值。 如上图

上图的大致说明:

1、Collection是一个接口,是高度抽象出来的集合,它包含了集合的基本操作和属性。Collection包含了List和Set两大分支。

  • List是一个有序的队列,每一个元素都有它的索引。第一个元素的索引值是0。List的实现LinkedList, ArrayList,Vector。
  • Set是一个不允许有重复元素的集合。Set的实现类有HastSet和TreeSet。HashSet依赖于HashMap,它实际上是通过HashMap实现的;TreeSet依赖于TreeMap,它实际上是通过TreeMap实现的。

2、Map是一个映射接口,即key-value键值对。Map中的每一个元素包含“一个key”和“key对应的value”。AbstractMap是个抽象类,它实现了Map接口中的大部分API。而HashMap,TreeMap,WeakHashMap都是继承于AbstractMap。Hashtable虽然继承于Dictionary,但它实现了Map接口。

ArrayList 和 LinkedList 的区别

ArrayList 是 List 接口的一种实现,它是使用数组来实现的。
LinkedList 是 List 接口的一种实现,它是使用链表来实现的。
ArrayList 遍历和查找元素比较快。LinkedList 遍历和查找元素比较慢。
ArrayList 添加、删除元素比较慢。LinkedList 添加、删除元素比较快。

Set、List、Map的区别

List集合是有序集合,集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问。
Set集合是无序集合,集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问(也是集合里元素不允许重复的原因)。
Map集合中保存Key-value对形式的元素,访问时只能根据每项元素的key来访问其value。

详细来看一下图中的接口与类

1、Collection接口

Collection接口是处理对象集合的根接口,其中定义了很多对元素进行操作的方法。Collection接口有两个主要的子接口List和Set,注意Map不是Collection的子接口
Collection接口有许多方法,等会看子类再说明

其子类

  1. List
  2. Set
  3. Vector

List接口
List集合代表一个有序集合,集合中每个元素都有其对应的顺序索引。List集合允许使用重复元素,可以通过索引来访问指定位置的集合元素。

(1)ArrayList
ArrayList是一个动态数组,也是我们最常用的集合。它允许任何符合规则的元素插入甚至包括null。每一个ArrayList都有一个初始容量(10),该容量代表了数组的大小。随着容器中的元素不断增加,容器的大小也会随着增加。在每次向容器中增加元素的同时都会进行容量检查,当快溢出时,就会进行扩容操作。所以如果我们明确所插入元素的多少,最好指定一个初始容量值,避免过多的进行扩容操作而浪费时间、效率。

常用的一些方法如下

方法名说明
boolean add(Object o)在列表的末尾顺序添加元素,起始索引位置从O开始
void add(int index,Objecto)在指定的索引位置添加元素。索引位置必须介于0和列表中元素个数之间
int size()返回列表中的元素个数
Object get(int index)返回指定索引位置处的元素。取出的元素是Object类型,使用前需要进行强制类型转换
boolean contains(Objecto)判断列表中是否存在指定元素
boolean remove(Object o)从列表中删除元素
Object remove(int index)从列表中删除指定位置元素,起始索引位置从0开始
。。。。。。。。。

代码示例:

List dogs = new ArrayList()
dogs.add(ououDog);
dogs.add(vayaDog);
dogs.add(meimeiDog);
dogs.add(2, feifeiDog);
System.out.println(“共计有"+dogs.size()+"条狗狗。");
System.out.println("分别是:");
for (int i = o; i< dogs.size(); i++)   for循环
Dog dog = (Dog) dogs.get(i);
.......

(2)LinkedList
同样实现List接口的LinkedList与ArrayList不同,ArrayList是一个动态数组,而LinkedList是一个双向链表。
由于实现的方式不同,LinkedList不能随机访问,它所有的操作都是要按照双重链表的需要执行。在列表中索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。这样做的好处就是可以通过较低的代价在List中进行插入和删除操作。

与ArrayList一样,LinkedList也是非同步的。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:

常用的一些方法如下:

方法说明
void addEirst(Object o)在列表的首部添加元素
void addLast(Object o)在列表的末尾添加元素
Object getEirst()返回列表中的第一个元素
object getLast()返回列表中的最后一个元素
Object removeFirst()删除并返回列表中的第一个元素
Object removeLast()删除并返回列表中的最后一个元素
。。。。。。。。。。。

代码示例

LinkedList dogs = new LinkedList();
dogs.add(ououDog);
dogs.add(yayaDog);
dogs.addLast(meimeiDog);
dogs.addFirst(feifeiDog);

Dog doaFirst=(Dog)dogs.getFirst();
stem.out.println(“第一条狗狗昵称是"+dogFirst.getName() );

Dog doaLast= (Dog)dogs.getLast();
System.out.println(“最后一条狗狗昵称是"+dogLast.getName());

dogs.removeFirst();
dogs.xemoxeLast();

(3)Vector
与ArrayList相似,但是Vector是同步的。所以说Vector是线程安全的动态数组。它的操作与ArrayList几乎一样。
以下是ArrayList和Vector的不同点:

1)Vector是同步的,而ArrayList不是。然而,如果你寻求在迭代的时候对列表进行改变,你应该使用CopyOnWriteArrayList。
(2)ArrayList比Vector快,它因为有同步,不会过载。
(3)ArrayList更加通用,因为我们可以使用Collections工具类轻易地获取同步列表和只读列表。

Set接口
Set是一种不包括重复元素的Collection。它维持它自己的内部排序,所以随机访问没有任何意义。与List一样,它同样允许null的存在但是仅有一个。由于Set接口的特殊性,所有传入Set集合中的元素都必须不同。
注意:虽然Set中元素没有顺序,但是元素在set中的位置是由该元素的HashCode决定的,其具体位置其实是固定的。

举一个例子:对象A和对象B,本来是不同的两个对象,正常情况下它们是能够放入到Set里面的,但是如果对象A和B的都重写了hashcode和equals方法,并且重写后的hashcode和equals方法是相同的话。那么A和B是不能同时放入到Set集合中去的,也就是Set集合中的去重和hashcode与equals方法直接相关。
代码:

public class Test 
public static void main(String[] args)  
     Set<String> set=new HashSet<String>(); 
     set.add("Hello"); 
     set.add("world"); 
     set.add("Hello"); 
     System.out.println("集合的尺寸为:"+set.size()); 
     System.out.println("集合中的元素为:"+set.toString()); 
   


======
运行结果
集合的尺寸为:2
集合中的元素为:[world, Hello]

(1)HashSet
HashSet 是一个没有重复元素的集合。它是由HashMap实现的,不保证元素的顺序(这里所说的没有顺序是指:元素插入的顺序与输出的顺序不一致),而且HashSet允许使用null 元素。HashSet是非同步的,如果多个线程同时访问一个哈希set,而其中至少一个线程修改了该set,那么它必须保持外部同步。 HashSet按Hash算法来存储集合的元素,因此具有很好的存取和查找性能。

注意:a.HashSet中存放null值。HashSet中是允许存入null值的,但是在HashSet中仅仅能够存入一个null值。

代码示例:

Set set=new HashSet();

String s1=new String("java");
string s2=s1;

String s3=new String("JAVA");
set.add(s1);
set.add(s2);
set.add(s3):

System.out.println(set.size());

(2)LinkedHashSet
LinkedHashSet继承自HashSet,其底层是基于LinkedHashMap来实现的,有序,非同步。LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。

(3)TreeSet
TreeSet是一个有序集合,其底层是基于TreeMap实现的,非线程安全。TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。当我们构造TreeSet时,若使用不带参数的构造函数,则TreeSet的使用自然比较器;若用户需要使用自定义的比较器,则需要使用带比较器的参数。

  • 注意:TreeSet集合不是通过hashcode和equals函数来比较元素的.它是通过compare或者comparaeTo函数来判断元素是否相等.compare函数通过判断两个对象的id,相同的id判断为重复元素,不会被加入到集合中。

2、Map接口
Map与List、Set接口不同,它是由一系列键值对组成的集合,提供了key到Value的映射。同时它也没有继承Collection。在Map中它保证了key与value之间的一一对应关系。也就是说一个key对应一个value,所以它不能存在相同的key值,当然value值可以相同。

一些Map接口的常用方法

方法名说明
Object put(Object key, Object val)以“键-值对”的方式进行存储
object get (Object key)根据键返回相关联的值,如果不存在指定的键,返回null
Object remove (Object key)删除由指定的键映射的“键-值对”
int size()返回元素个数
Set keySet ()返回键的集合
collection values ()返回值的集合
boolean containsKey (Object key)如果存在由指定的键映射的“键-值对”,返回true
。。。更多参考官网

(1)HashMap
以哈希表数据结构实现,查找对象时通过哈希函数计算其位置,它是为快速查询而设计的,其内部定义了一个hash表数组(Entry[] table),元素会通过哈希转换函数将元素的哈希地址转换成数组中存放的索引,如果有冲突,则使用散列链表的形式将所有相同哈希地址的元素串起来,可能通过查看HashMap.Entry的源码它是一个单链表结构。

代码示例

Map countries = new HashMap();

countrie.s.put("CN", "中华人民共和国");
countries.put("RU","俄罗斯联邦");
countries.put("FR","法兰西共和国");
countries.put("us","美利坚合众国");

String country = (String) countries.get("CN");

System.out.printIn("Map中共有"+countries.size()+"组数据");
countrie.s.remoxe("FR");

System.out.println("Map中包含FR的key"+cauntries.containsKey(FR"));

System.out.orintln(countries.keySet());
System.out.println(countries.values());
System.out.println(countries);

(2)LinkedHashMap

  • LinkedHashMap是HashMap的一个子类,它保留插入的顺序,如果需要输出的顺序和输入时的相同,那么就选用LinkedHashMap。
  • LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
  • 根据链表中元素的顺序可以分为:按插入顺序的链表,和按访问顺序(调用get方法)的链表。默认是按插入顺序排序,如果指定按访问顺序排序,那么调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。

(3)TreeMap

  • TreeMap 是一个有序的key-value集合,非同步,基于红黑树(Red-Blacktree)实现,每一个key-value节点作为红黑树的一个节点。TreeMap存储时会进行排序的,会根据key来对key-value键值对进行排序,其中排序方式也是分为两种,一种是自然排序,一种是定制排序,具体取决于使用的构造方法。
  • 自然排序:TreeMap中所有的key必须实现Comparable接口,并且所有的key都应该是同一个类的对象,否则会报ClassCastException异常。
  • 定制排序:定义TreeMap时,创建一个comparator对象,该对象对所有的treeMap中所有的key值进行排序,采用定制排序的时候不需要TreeMap中所有的key必须实现Comparable接口。
  • TreeMap判断两个元素相等的标准:两个key通过compareTo()方法返回0,则认为这两个key相等。

三、使用java集合类的好处

  • (1)降低编程难度:在编程中会经常需要链表、向量等集合类,如果自己动手写代码实现这些类,需要花费较多的时间和精力。调用Java中提供的这些接口和类,可以很容易的处理数据。
  • (2)提升程序的运行速度和质量:Java提供的集合类具有较高的质量,运行时速度也较快。使用这些集合类提供的数据结构,程序员可以从“重复造轮子”中解脱出来,将精力专注于提升程序的质量和性能。
  • (3)无需再学习新的APl:借助泛型,只要了解了这些类的使用方法,就可以将它们应用到很多数据类型中。如果知道了LinkedList的使用方法,也会知道LinkedList怎么用,则无需为每一种数据类型学习不同的API。
  • (4)增加代码重用性:也是借助泛型,就算对集合类中的元素类型进行了修改,集合类相关的代码也几乎不用修改。

以上是关于java集合的主要内容,如果未能解决你的问题,请参考以下文章

Java面试题目集合

搞定Java集合类区别

java集合 list与SetMap区别

java 常用集合list与SetMap区别及适用场景总结

Java基础知识盘点- 集合篇

java-通过 HashMapHashSet 的源码分析其 Hash 存储机制