java集合

377 阅读9分钟

集合是java中常用的一个机制。上次,我在想回头重新看集合的时候,发现网上对集合的整理大多都非常糟,要么过于繁琐,要么过于简洁。于是,我决心自己整理一篇集合的文章,作为自己学过集合的一个总结。

老规矩,我会把我看过的给我印象比较深刻的文章贴在最后,作为参考文献。

集合的概述

(1)Java集合类存放于 java.util 包中,是一个用来存放对象的容器。

  • 集合只能存放对象。比如你存一个 int 型数据1 放入集合中,其实它是自动转换成 Integer类后存入的,Java中每一种基本类型都有对应的引用类型。

  • 集合存放的是多个对象的引用,对象本身还是放在堆内存中。

  • 集合可以存放不同类型,不限数量的数据类型。

(2)Java 集合可分为 Set、List 和 Map 三种大体系

  • Set:存取无序,元素不可以重复

  • List:存取有序,有索引,可以根据索引来进行取值,元素可以重复

  • Map:具有映射关系的集合

(3)在 JDK5 之后,增加了泛型,Java 集合可以记住容器中对象的数据类型

set集合

Hashset集合

特点、方法

HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。我们大多数时候说的set集合指的都是HashSet。

HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。HashSet 具有以下特点:

  • 不能保证元素的排列顺序
  • 不可重复(hashcode不相同)
  • HashSet 不是线程安全的
  • 集合元素可以使 null

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置

存在set集合哪个位置由这个值的hashcode决定,而不是按先来后到

如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功

基本操作

public class test3 {
    public static void main(String[] args) {
    //	Set set = new HashSet();//创建set集合-方式1
	Set <Object> set = new HashSet<Object>();//创建set集合-方式2。与上面的方式1等价

	set.add(1);//添加元素
	set.add("a");

	set.remove(1);//移除元素
    
        System.out.println(set.contains(1));//判断是否包含元素,存在返回true
	
	set.clear();//清空集合

遍历

  1. 使用 Iterator 接口遍历集合元素

Iterator 接口主要用于遍历 Collection 集合中的元素,Iterator 对象也被称为迭代器

Iterator 接口隐藏了各种 Collection 实现类的底层细节,向应用程序提供了遍历 Collection 集合元素的统一编程接口

Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。

  1. 使用 foreach 循环遍历集合元素

Java 5 提供了 foreach 循环迭代访问 Collection

		set.add("a");
    		set.add("b");
    		set.add("c");
    		set.add("d");
//		set.add("d");//set集合是存的值是不重复
    		set.add(1);
    		set.add(true);
    		set.add(null);//Hashset允许使用null,有且仅有一个元素为null
    		System.out.println(set);//输出集合:[null, a, 1, b, c, d, true]	
      
                //使用迭代器遍历集合
		Iterator it = set.iterator();
		while(it.hasNext()){
			System.out.println(it.next());
		}
		
		//for each迭代集合,推荐使用这种
		for(Object obj : set){//这个的意思是把set的每一个值取出来,赋值给obj,直到循环set的所有值
			System.out.println(obj);
		}
  
                System.out.println(set.size());//获取集合的元素个数

泛型

    		//如果想要让集合只能存同样类型的对象,怎么做
    		//使用泛型
    		Set<String> set1 = new HashSet<String>();//比如指定String为集合的泛型,那么这个集合不能存String类型之外的数据
		
    		set1.add("sbc");
  //		set1.add(1);

Treeset集合

TreeSet 是 SortedSet 接口的实现类

TreeSet 特点:存取无序,元素唯一,可以进行排序(排序是在添加的时候进行排序)

TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序

自然排序

TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列

  • 如果 this > obj,返回正数 1
  • 如果 this < obj,返回负数 -1
  • 如果 this = obj,返回 0 ,则认为这两个对象相等

必须放入同样类的对象.(默认会进行排序) 否则可能会发生类型转换异常.我们可以使用泛型来进行限制

public class Test4 {
    public static void main(String[] args) {
	Set<Integer> set = new TreeSet<Integer>();
	//TreeSet自然排序
	set.add(5);
	set.add(2);
	set.add(4);
	set.add(3);
	System.out.println(set);//输出集合:[2, 3, 4, 5]
      
    	set.remove(5);//移除元素
     
        System.out.println(set.contains(3));//判断是否包含元素,存在返回true
        
    	set.clear();//清空集合
    		
    	//使用迭代器遍历集合
    	Iterator<Integer> it = set.iterator();
    	while(it.hasNext()){
    		System.out.println(it.next());
    	}
    		
    	//for each迭代集合,推荐使用这种
    	for(Integer i : set){
    		System.out.println(i);
	}

定制排序

如果需要实现定制排序,则需要在创建 TreeSet 集合对象时,提供一个 Comparator 接口的实现类对象。由该 Comparator 对象负责集合元素的排序逻辑。

List集合

特点

  • List 代表一个元素有序、且可重复的集合,集合中的每个元素都有其对应的顺序索引
  • List 允许使用重复元素,可以通过索引来访问指定位置的集合元素。
  • List 默认按元素的添加顺序设置元素的索引。
  • List 集合里添加了一些根据索引来操作集合元素的方法

ArrayList 和 Vector

ArrayList 和 Vector 是 List 接口的两个典型实现

两者的区别:

  • Vector是一个古老的集合,通常建议使用 ArrayList

  • ArrayList 是线程不安全的,而 Vector 是线程安全的

  • 即使为保证 List 集合线程安全,也不推荐使用 Vector

接口实现

基本操作

public class Test5 {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("b");//第一个,索引下标0
		list.add("d");//索引下标1
		list.add("c");//索引下标2
		list.add("a");//索引下标3
		list.add("d");//允许使用重复元素
		
		System.out.println(list);//结果:[b, d, c, a, d]
		System.out.println(list.get(2));//通过索引来访问指定位置的集合元素.结果:c
		
		list.add(1,"f");//在指定索引下标的位置插入数据
		System.out.println(list);//结果:[b, f, d, c, a, d]
		
		List<String> m = new ArrayList<String>();
		m.add("123");
		m.add("456");
		
		list.addAll(2, m);//在指定索引下标的位置插入集合
		
		System.out.println(list);//结果:[b, f, 123, 456, d, c, a, d]
		
		System.out.println(list.indexOf("d"));//获取指定元素在集合中第一次出现的索引下标.结果:4
		System.out.println(list.lastIndexOf("d"));//获取指定元素在集合中最后一次出现的索引下标.结果:7
		
		list.remove(2);//根据指定的索引下标移除元素
		System.out.println(list);//结果:[b, f, 456, d, c, a, d]
		
		list.set(1, "ff");//根据指定的索引下标修改元素
		System.out.println(list);//结果:[b, ff, 456, d, c, a, d]
		
		//根据索引下标的起始位置截取一段元素形参一个新的集合,截取的时候,包含开始的索引不包含结束时的索引
		List<String> sublist =  list.subList(2, 4);//取索引下标在大于等于2,小于4的元素
		
		System.out.println(sublist);//结果:[456, d]
		
		System.out.println(list.size());//集合的长度.结果:7
	}
}

Map集合

HashMap集合

特点

  • Map 用于保存两组具有映射关系的数据,一组值用于保存 Map 里的 Key,另外一组用于保存 Map 里的 Value

  • Map 中的 key 和 value 都可以是任何引用类型的数据

  • Map 中的 Key 不允许重复,即同一个 Map 对象的任何两个 Key 通过 equals 方法比较中返回 false

  • Key 和 Value 之间存在单向一对一关系,即通过指定的 Key 总能找到唯一的,确定的 Value。

Map 接口与HashMap类

基本操作

public class Test6 {
	public static void main(String[] args) {
		//介绍Map集合的方法
		Map<String, Integer> map = new HashMap<String, Integer>();
		map.put("b", 1);//添加数据,put(k,v)
		map.put("c", 2);
		map.put("e", 2);
		System.out.println(map);//结果:{b=1, c=2, e=2}
		
		System.out.println(map.get("e"));//根据key取value值. 结果:2
		
		map.remove("c");//根据key移除键值对
		System.out.println(map);//结果:{b=1, e=2}
		
		System.out.println(map.size());//map集合的长度. 结果:2
		
		System.out.println(map.containsKey("a"));//判断当前的map集合是否包含指定的key
		
		System.out.println(map.containsValue(2));//判断当前的map集合是否包含指定的value
		
//		map.clear();//清空集合
		
		//介绍Map集合的遍历
		Set<String> keys = map.keySet();//获取map集合的key的集合
		System.out.println(keys);//结果:[b, e]
		
		map.values();//获取集合的所有value值
		System.out.println(map.values());//结果:[1, 2]
		
		//遍历map集合,通过map.keySet();
		for(String key : keys){
			System.out.println("key: " + key + ", value: " + map.get(key));
		}
		
		//通过map.entrySet();遍历map集合
		Set<Entry<String, Integer>> entrys = map.entrySet();
		for(Entry<String, Integer> en : entrys){
			System.out.println("key: " + en.getKey() + ", value: " + en.getValue());
		}

HashMap & Hashtable

HashMap 和 Hashtable 是 Map 接口的两个典型实现类,区别:

  • Hashtable 是一个古老的 Map 实现类,不建议使用
  • Hashtable 是一个线程安全的 Map 实现,但 HashMap 是线程不安全的。
  • Hashtable 不允许使用 null 作为 key 和 value,而 HashMap 可以

与 HashSet 集合不能保证元素的顺序一样,Hashtable 、HashMap 也不能保证其中 key-value 对的顺序

  • Hashtable 、HashMap 判断两个 Key 相等的标准是:两个 Key 通过 equals 方法返回 true,hashCode 值也相等。

  • Hashtable 、HashMap 判断两个 Value 相等的标准是:两个 Value 通过 equalHashMap 判断两个 Values 方法返回 true

TreeMap集合

TreeMap 存储 Key-Value 对时,需要根据 Key 对 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态。

TreeMap 的 Key 的排序:

  • 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException

  • 定制排序(了解):创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口

注:

  1. Comparable接口是在java.lang类中的,而Comparator接口是在java.util类中的。

  2. Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。

     	//TreeMap的自然排序是英文字典排序
     	Map<Integer,String> map = new TreeMap<Integer, String>();
     	map.put(4, "a");
     	map.put(2, "a");
     	map.put(3, "a");
     	map.put(1, "a");
     	
     	System.out.println(map);//结果:{1=a, 2=a, 3=a, 4=a}
     	
     	Map<String,String> map1 = new TreeMap<String, String>();
     	map1.put("b", "b");
     	map1.put("c", "c");
     	map1.put("d", "d");
     	map1.put("a", "a");
     	map1.put("ab", "ab");
     	map1.put("1", "ab");
     	map1.put("10", "ab");
     	
     	System.out.println(map1);//结果:{1=ab, 10=ab, a=a, ab=ab, b=b, c=c, d=d} 
    

参考文献

Java 集合框架 www.runoob.com/java/java-c…

java集合入门和深入学习,看这篇就差不多了 juejin.cn/post/684490…

Java常用集合类及其区别 blog.csdn.net/zhj87097558… (常用类)

java集合的各种操作 www.51gjie.com/java/654.ht… (操作详解)

Set之HashSet和TreeSet介绍 blog.csdn.net/u010648555/…