Java集合类

一:集合的由来通常,我们的程序需要根据程序运行时才知道创建多少个对象。但若非程序运行,程序开发阶段,我们根本不知道到底需要多少个数量的对象,甚至不知道它的准确类型。为了满足这些常规的编程需要,我们要求能在任何时候,任何地点创建任意数量的对象,而这些对象用什么来容纳呢?我们首先想到了数组,但是数组只能放统一类型的数据,而且其长度是固定的,那怎么办呢?集合便应运而生了!
集合类存放于java.util包中。 

        注意:

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

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

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

二:集合的框架:

三:集合详解

1:Collection接口

Collection接口是List,Set,Queue接口的父接口。

下面是一个Collection集合使用的例子:

import java.util.*;

public class CollectionTest {
	public static void main(String[] args)
	{
		Collection c = new ArrayList();
		//添加元素
		c.add("孙悟空");
		c.add(6);//自动装箱
		c.add("Java");
		System.out.println("c集合的元素个数为:"+c.size());   //输出2
		//删除指定元素
		c.remove(6);
		System.out.println("c集合的元素个数为:"+c.size());   //输出1
		//判断是否包含指定字符串
		System.out.println("c集合是否包含\"孙悟空\"字符串:"
				+c.contains("孙悟空"));   //输出true
		c.add("猪八戒");
		System.out.println("c集合的元素" + c);
		Collection books = new HashSet();
		books.add("数学");
		books.add("Java");
		System.out.println("c集合是否完全包含books集合?"
				+ c.containsAll(books));    //输出false
		//用c集合减去books集合里的元素
		c.removeAll(books);
		System.out.println("c集合的元素" + c);
		//删除c集合里面所有的元素
		c.clear();
		System.out.println("c集合的元素" + c);
		//控制books集合里只剩下c集合里也包含的元素
		books.retainAll(c);
		System.out.println("books集合的元素:" + books);
	}
  }

运行结果:


把运行结果和代码结合来看,可以看出Collection的用法有:添加元素、删除元素、返回Collection集合的元素个数以及清空整个集合等。

2:Iterator接口:

Iterator接口也是Java集合框架的成员,但它与Collection系列、Map系列的集合不一样:Collection系列集合、Map系列集合主要用于盛装其他对象,而Iterator则主要用于遍历(即迭代访问)Collection集合中的元素,Iterator对象也被称为迭代器。

Iterator接口里定义了如下3个主要方法:

       Object next():返回迭代器刚越过的元素的引用,返回值是 Object,需要强制转换成自己需要的类型
  boolean hasNext():判断容器内是否还有可供访问的元素
  void remove():删除迭代器刚越过的元素

下面程序示范了通过Iterator接口来遍历集合元素

import java.util.*;

public class Iteratortest {
	public static void main(String[] args)
	{
		//创建一个集合
		Collection books = new HashSet();
		books.add("数学");
		books.add("语文");
		books.add("英语");
		//获取books集合对应的迭代器
		Iterator it = books.iterator();
		while(it.hasNext())
		{
			//it.next()方法返回的数据类型是Object类型,所以要强制转换
			String book = (String)it.next();
			System.out.println(book);
			if(book.equals("语文"))
			{
				//从集合中删除上一次next()方法返回的元素
				it.remove();
			}
		}
		System.out.println(books);
	}
}

注意:1:Iterator接口必须依附于Collection接口,若有一个Iterator对象,则必然有一个与之关联的Collection对象。

2:当使用Iterator迭代器访问Collection集合元素时,Collection集合里的元素不能被改变,只有通过Iterator的remove()方法删除上一次next()方法返回的集合元素才可以。

3:Set集合

Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中,则添加操作失败,add()方法返回false,且新元素不会被加入。

(1) HashSetSet接口的典型实现。HashSet按Hash算法来存储集合中的元素,因此具有很好的存储和查找性能。

①、HashSet:不能保证元素的顺序;不可重复;不是线程安全的;集合元素可以为 NULL;

、对于 HashSet: 如果两个对象通过 equals() 方法返回 true,这两个对象的 hashCode 值也应该相同。
   1、当向HashSet集合中存入一个元素时,HashSet会先调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据hashCode值决定该对象在HashSet中的存储位置
   1.1、如果 hashCode 值不同,直接把该元素存储到 hashCode() 指定的位置
   1.2、如果 hashCode 值相同,那么会继续判断该元素和集合对象的 equals() 作比较
     1.2.1、hashCode 相同,equals 为 true,则视为同一个对象,不保存在 hashSet()中
     1.2.2、hashCode 相同,equals 为 false,则存储在之前对象同槽位的链表上,这非常麻烦,我们应该约束这种情况,即保证:如果两个对象通过 equals() 方法返回 true,这两个对象的 hashCode 值也应该相同。
注意:每一个存储到哈希表中的对象,都得提供 hashCode() 和 equals() 方法的实现,用来判断是否是同一个对象
  对于 HashSet 集合,我们要保证如果两个对象通过 equals() 方法返回 true,这两个对象的 hashCode 值也应该相同。

  (2) LinkedHashSet:
    ①、不可以重复,有序
  因为底层采用链表和哈希表的算法。链表保证元素的添加顺序,哈希表保证元素的唯一性

(3)TreeSet:
        TreeSet:有序;不可重复,底层使用 红黑树算法,擅长于范围查询。
  *  如果使用 TreeSet() 无参数的构造器创建一个 TreeSet 对象, 则要求放入其中的元素的类必须实现 Comparable 接口所以, 在其中不能放入 null 元素
       *  必须放入同样类的对象.(默认会进行排序) 否则可能会发生类型转换异常.我们可以使用泛型来进行限制
下面程序测试了TreeSet的通用用法
import java.util.*;

public class TreeSetTest {
	public static void main(String[] args)
	{
		TreeSet nums = new TreeSet();
		//向TreeSet中添加四个Integer对象
		nums.add(5);
		nums.add(2);
		nums.add(10);
		nums.add(-9);
		//输出集合元素,看到集合元素已经处于排序状态
		System.out.println(nums);
		//输出第一个元素
		System.out.println(nums.first());
		//输出最后一个元素
		System.out.println(nums.last());
		//返回小于4的子集
		System.out.println(nums.headSet(4));
		//返回大于5的子集,如果Set中包含5,子集中还包含5
		System.out.println(nums.tailSet(5));
	}
}

下面是运行结果:


从上面程序的运行结果可以看出,TreeSet并不是根据元素的插入顺序进行排序的,而是根据元素的实际值的大小进行排序的。

自然排序:

添加自定义对象的时候,必须要实现 Comparable 接口,并要覆盖 compareTo(Object obj) 方法来自定义比较规则

    如果 this > obj,返回正数 1

    如果 this < obj,返回负数 -1

    如果 this = obj,返回 0 ,则认为这两个对象相等

注意:向TreeSet中添加的应该是同一类对象

import java.util.*;

public class TreeSetTest {
    public static void main(String[] args) {
        Person p1 = new Person(20);
        Person p2 = new Person(35);
        Person p3 = new Person(18);s
        Set<Person> set = new TreeSet<>(new Person());
        set.add(p1);
        set.add(p2);
        set.add(p3);
        System.out.println(set);  //结果为[18, 20, 35]
    }
}
 
class Person implements Comparator<Person>{
    public int age;
    public Person(){}
    public Person(int age)
    {
        this.age = age;
    }
    @Override
    /***
     * 根据年龄大小进行排序
     */
    public int compare(Person o1, Person o2) 
    {
        if(o1.age > o2.age)
        {
            return 1;
        }
        else if(o1.age < o2.age)
        {
            return -1;
        }
        else
        {
            return 0;
        }
    }
     
    @Override
    public String toString() 
    {
        return ""+this.age;
    }
}

  定制排序: 

创建 TreeSet 对象时, 传入 Comparator 接口的实现类. 要求: Comparator 接口的 compare 方法的返回值和 两个元素的 equals() 方法具有一致的返回值 

以上三个 Set 接口的实现类比较:
  共同点:
                    1、都不允许元素重复
      2、都不是线程安全的类。
  不同点:
    HashSet:不保证元素的添加顺序,底层采用哈希表算法,查询效率高。判断两个元素是否相等,equals() 方法返回 true,hashCode() 值相等。即要求存入 HashSet 中的元素要覆盖 equals() 方法和 hashCode()方法
 
    LinkedHashSet:HashSet 的子类,底层采用了哈希表算法以及链表算法,既保证了元素的添加顺序,也保证了查询效率。但是整体性能要低于 HashSet    
 
    TreeSet:不保证元素的添加顺序,但是会对集合中的元素进行排序。底层采用红-黑树算法

 4:List集合

List集合代表一个有序、可重复的集合,集合中每个元素都有其对应的顺序索引。List集合默认按添加顺序设置元素的索引。 所有的List中可以有null元素

1、List 接口的三个典型实现:

  ①、List list1 = new ArrayList();
    底层数据结构是数组,查询快,增删慢;线程不安全,效率高
   ②、List list2 = new Vector();
    底层数据结构是数组,查询快,增删慢;线程安全,效率低,几乎已经淘汰了这个集合
   ③、List list3 = new LinkedList();
    底层数据结构是链表,查询慢,增删快;线程不安全,效率高

下面程序示范了List集合的常规用法

import java.util.ArrayList;
import java.util.List;

public class ListTest {
	public static void main(String[] args)
	{
		List books = new ArrayList();
		//向books集合中添加三个元素
		books.add("语文");
		books.add("数学");
		books.add("英语");
		System.out.println(books);
		//将新字符串对象插入在二个位置
		books.add(1 , new String("Java"));
		for(int i = 0 ; i < books.size() ; i++)
		{
			System.out.println(books.get(i));
		}
		//删除第三个元素
		books.remove(2);
		System.out.println(books);
		//判断指定元素在List集合中的位置,输出0,表示在第一位
		System.out.println(books.indexOf(new String("语文")));
		//将第二个元素替换成新的字符串对象
		books.set(1, new String("C语言"));
		System.out.println(books);
		//将books集合的第二个元素(包括)到第三个元素(不包括)截取成子集合
		System.out.println(books.subList(1 , 2));
	}
}

Array.ArrayList是一个固定长度的List集合,程序只能遍历访问该集合里的元素,不可以增加、删除该集合里的元素。

LinkedList:LinkedList是List集合,但它还实现了Deque接口,可以被当作双端队列来使用,因此既可以被当成”栈“来使用,也可以当成队列来使用

下面程序简单示范了LinkedList集合的用法:

import java.util.LinkedList;

public class LinkedListTest {
	public static void main(String[] args)
	{
		LinkedList books = new LinkedList();
		//将字符串元素加入队列的尾部
		books.offer("语文");
		//将一个字符串元素加入栈的顶部
		books.push("数学");
		//将字符串元素添加到队列的头部(相当于栈的顶部)
		books.offerFirst("英语");
		//以List的方式(按索引访问的方式)来遍历集合元素
		for(int i = 0; i < books.size() ; i++)
		{
			System.out.println("遍历中: "+ books.get(i));
		}
		//访问并不删除栈顶元素
		System.out.println(books.peekFirst());
		//访问并不删除队列的最后一个元素
		System.out.println(books.peekLast());
		//将栈顶元素弹出“栈”
		System.out.println(books.pop());
		System.out.println(books);
		//访问并删除队列的最后一个元素
		System.out.println(books.pollLast());
		//输出数学
		System.out.println(books);
	}
}

5:Map集合:

  Map是一种依照键(key)存储元素的容器,键(key)很像下标,在List中下标是整数。在Map中键(key)可以使任意类型的对象。Map中不能有重复的键(Key),每个键(key)都有一个对应的值(value)。
  一个键(key)和它对应的值构成map集合中的一个元素。
 Map中的元素是两个对象,一个对象作为键,一个对象作为值。键不可以重复,但是值可以重复。

1、严格来说 Map 并不是一个集合,而是两个集合之间 的映射关系。
2、这两个集合没每一条数据通过映射关系,我们可以看成是一条数据。即 Entry(key,value)。Map 可以看成是由多个 Entry 组成。

3、因为 Map 集合即没有实现于 Collection 接口,也没有实现 Iterable 接口,所以不能对 Map 集合进行 for-each 遍历。

下面程序示范了Map的基本功能:

import java.util.HashMap;
import java.util.Map;

public class MapTest {
	public static void main(String[] args)
	{
		Map map = new HashMap();
		map.put("语文", 109);
		map.put("数学",10);
		map.put("英语", 79);
		//value可以重复
		map.put("Java", 109);
		System.out.println(map);
		//判断是否含有指定key
		System.out.println("是否包含值为 语文 key:"+map.containsKey("语文"));   //输出true
		//判断是否包含指定value
		System.out.println("是否包含值为 109 value: "+ map.containsValue(109));  //输出true
		//获取Map集合的所以key组成的集合,通过遍历key来实现遍历所以的key-value对
		for(Object key : map.keySet() )
		{
			//map.get(key)方法获取指定key对应的value
			System.out.println(key + "-->" + map.get(key));
		}
		map.remove("数学");
		System.out.println(map);
	}
}

Map实现类
1:HashMap:
线程不安全,效率高。允许null键和null值
是基于哈希表的Map接口实现。哈希表的作用是用来保证键的唯一性的。
常用实例化方法: 
       new HashMap< Object, Object>();
2:Hashtable:
线程安全,效率低。不允许null键和null值

类似于HashSet,HashMap、Hashtable判断两个key相等的标准也是:两个key通过equals()方法比较返回true,两个key的hashCode值也相等。

HashMap、Hashtable判断两个value相等的标准更简单:只要两个对象通过equals()方法比较返回true即可。

 3:LinkedHashMap:
是基于Map接口的哈希表和链接列表实现,有序
由哈希表保证键的唯一性
由链表保证键盘的有序(存储和取出的顺序一致)
常用实例化方法: 
       new LinkedHashMap< Object, Object>();
4: treeMap:
TreeMap:是基于红黑树的Map接口的实现。
构造方法: 
       TreeMap() 使用键的自然顺序构造一个新的、空的树映射。 
       TreeMap(Comparator< ? super K> comparator) 构造一个新的、空的树映射,该映射根据给定比较器进行排序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值