第10章 集合类

目录

10.1 集合类概述

10.2 Collection接口

10.3 List 集合

10.3.1 List接口

10.3.2 List接口的实现类

10.3.3 Iterator迭代器

10.4 Set集合

10.4.1 Set接口

10.4.2 Set接口的实现类

10.4.3 TreeSet的两种排序方法 

10.5 Map集合

10.5.1 Map接口

10.5.2 接口的实现类

10.6 集合的使用场所


10.1 集合类概述

         java.util包中提供了一些集合类,这些集合类又被称为容器。提到容器不难想到数组,集合类与数组的不同之处是,数组的长度是固定的,集合的长度是可变的;数组用来存放基本类型的数据,集合用来存放对象的引用。常用的集合有List 集合、Set 集合和Map集合,其中List与Set继承了Collction接口,各接口还提供了不同的实现类。

10.2 Collection接口

        Collection接口是层次结构中的根接口。构成Collection的单位称为元素。Collection 接口通常不能直接使用,但该接口提供了添加元素、删除元素和管理数据的方法。由于List接口与Set接口都继承了Collection接口,因此这些方法对List集合与Set集合是通用的。

方法

功能描述

add(object e)

将指定的对象添加到该集合中

remove(object o)

将指定的对象从该集合中移除

isEmpty()

返回boolean值,用于判断当前集合是否为空

iterator()

返回在此collection的元素上进行迭代的迭代器,用于遍历集合中的对象

size()

返回int型值,获取该集合中元素的个数

10.3 List 集合

        List集合包括List接口以及List接口的所有实现类。List 集合中的元素允许重复,各元素的顺序就是对象插入的顺序。类似Java数组,用户可通过使用索引(元素在集合中的位置)来访问集合中的元素。

10.3.1 List接口

         List接口继承了Cllection接口,因此包含Colletion中的所有方法,此外,List接口还定义了以下两个非常重要的方法。

方法

功能描述

Get(int index)

获得指定索引位置的元素

Set(int index,object obj)

将集合中指定索引位置的对象修改为指定的对象

说明: 由于Cllection接口是List集合和Set集合的父接口,因此表中的方法对于List集合和Set集合都是通用的。

10.3.2 List接口的实现类

        List接口由于不能直接实例化,因此,在JDK中提供了其实现子类,最常用的实现子类有ArayList类与LinkedList类,分别如下。
        (1) ArrayList类的优点是实现了可变的数组,允许保存所有元素,包括null, 并可以根据索引位置对集合进行快速的随机访问;缺点是向指定的索引位置插入对象或删除对象的速度较慢,因为ArayList实质上是使用数组来保存集合中的元素的,在增加和删除指定位置的元素时,虚拟机会好建新的数组,效率低,所以在对元素做大量的增删操作时不适合使用ArayList集合。

        (2) LinkedList类采用链表结构保存对象,这种结构的优点是便于向集合中插入和删除对象,需要向集合中插入、删除对象时,使用LinkedList类实现的List 集合的效率较高;但对于随机访问集合中的对象,使用LinkedList类实现List集合的效率较低。

使用List集合时通常声明为List类型,可通过不同的实现类来实例化集合。

例如,分别通过ArrayList、LinkedList 类实例化List集合。代码如下:

List<E> list = new ArrayList<>( );

List<E> list2 = new LinkedList<>( );

在上面的代码中,E代表Java中的泛型。例如,如果集合中的元素为字符串类型,那么E可以修改为String。

        在项目中创建LstTest类,在主方法中创建List 集合对象,并使用add方法向集合中添加元素,然后随机生成一个集合长度范围内的索引,并使用get方法获取该索引对应的值:最后再使用renove方法移除集合中索引位置2处的值,并使用for循环遍历集合,输出所有的集合元素值。

import java.util.*;//导入要用到的包
public class ListTest {
	public static void main(String[] args) {//主方法
		List<String> list = new ArrayList<>();//创建集合对象
		list.add("a");//向集合添加元素
		list.add("b");//向集合添加元素
		list.add("c");//向集合添加元素
		int i = (int) (Math.random()*list.size());//获得0~2之间的随机数
		System.out.println("随机获取数组中的元素: "+list.get(i));
		list.remove(2);//将指定索引位置的元素从集合中移除
		System.out.println("将索引是'2'的元素从数组移除后,数组中的元素是:");
		for (int j = 0; j<list.size();j++) {//循环遍历集合
			System.out.println(list.get(j));//获取指定索引处的值
		}
	}
}

说明:与数组相同,集合的索引也是从0开始。 

10.3.3 Iterator迭代器

         在使用了for循环遍历List集合中的元素,那么有没有其他更加快捷有效的遍历集合中元素的方法呢?答案是肯定的,在java.util 包中提供了一个Iterator 接口,该接口是一个专门对Colletion进行迭代的迭代器。

方法

功能描述

Hasnext()

如果仍有元素可以迭代,则返回true

Next()

返回迭代的下一个元素

Remove()

从迭代器指向的collection中移迭代器返回的最后一个元素(可选操作)

注意:Iterator的next()方法返回的是Object。 

        程序中使用Iterator迭代器时,可以使用Collection接口中的iterator()方法返回一个Iterator对象。下面演示如何使用Iterator迭代器遍历集合。

        在项目中创建TeratorTeset类,在主方法中实例化集合对象,并向集合中添加元素, 最后通过lterator迭代器遍历集合,将集合中的对象以String形式输出。

import java.util.*;//导入要用到的包
public class IteratorTest {
	public static void main(String[] args) {//主方法
		Collection<String> list = new ArrayList<>();//实例化集合类对象
		list.add("a");//向集合添加元素
		list.add("b");//向集合添加元素
		list.add("c");//向集合添加元素
		Iterator<String> it = list.iterator();//创建迭代器
		while (it.hasNext()) {//判断是否有下一个元素
			String str= (String) it.next();//获取集合中元素
			System.out.println(str);
		}
	}
}

 

10.4 Set集合

        Set集合中的对象不按特定的方式排序,只是简单地把对象加入集合中,但Set集合中不能包含重复对象,Set集合由Set接口和Set接口的实现类组成。 

10.4.1 Set接口

         Set接口是一个不包含重复元素的集合,由于其继承了Collction接口,因此包含Collection 接口的所有方法。

注意:Set的构造有一个约束条件,传入Collection对象不能有重复值,必须小心操作可变对象(Mutable Object)。如果一个Set中的可变元素改变了自身状态导致Object.equals(Object)=true,则会出现一些问题。

        由于Set集合中不允许有重复元素出现,因此,在向Set集合中添加元素时,需要先判断元素是否已经存在,再确定是否执行添加操作。

10.4.2 Set接口的实现类

        Set接口常用的实现类有HashSet类与TreeSet类,分别如下。

        (1) HashSet是Set接口的一个实现类,它不允许有重复元素。HashSet主要依据哈希算法直接将元素指定到一个地址上。当向HashSet 集合中添加一个元素时,会调用equals方法来判断该位置是否有重复元素。判断是通过比较它们的HashCode来进行比较的。HashSet集合的常用方法都是重写了Set接口中的方法。此集合允许保存null。

        (2) TreeSet类不仅实现了Set接口,还实现了java.util.SortedSet接口,因此,TreeSet类实现的Set集合在遍历集合时按照自然顺序递增排序,也可以制定排序规则,让集合按照我们想要的方式进行排序。TreeSet 类新增的方法,此集合不能保存null。

返回

功能描述

first()

返回此set中当前第一个(最低)元素

last()

返回此set中当前最后一个(最高)元素

comparator()

返回对此set中的元素进行排序的比较器,如果此set使用自然顺序,则返回null

headset(E toElement)

返回一个新的set集合,新集合是toElement(不包含)之前的所有对象

subset(E fromElement,E toElement)

返回一个新的set集合,是fromElement(包含)对象与toElement(不包含)对象之间的所有对象

tailset(E fromElement)

返回一个新的set集合,新集合包含对象fromElement(包含)之后的所有对象

说明:比较器,即Comparator接口,它提供一个抽象方法compare(T o1, T o2),这个方法指定了两个对象的比较规则,如果o1大于o2,方法返回正数(通常为+1);如果o1等于o2,方法返回0;如果o1小于o2,方法返回负数( 通常为-1 )。
        还有另一个接口也能实现比较规则: Comparable。 它提供一个抽象方法compareTo(T o),将调用方法的对象与参数对象进行比较,返回值的规则与上面的Comparator. compare( )方法相同。
        如果想制定TreeSet的排序规则,可以在实例化TreeSet对象时,将一个已写好的比较器作为构造参数传入,或者让TreeSet中的所有元素都实现Comparable接口。

技巧:HashSet类和TreeSet类都是Set接口的实现类,它们当中都不允许有重复元素,但HashSet类不关心元素之间的顺序,而TreeSet类则在希望按照元素的自然顺序进行排序时使用(自然顺序的意思是与插入顺序无关,而是和元素本身的内容和特质有关,例如: abc 排在abd前面)。

import java.util.*;//导入要用到的包
public class HashSetTest {
	public static void main(String[] args) {//主方法
		Set set = new HashSet();//创建Set集合
		set.add("c");//向集合添加元素
		set.add("c");//向集合添加元素
		set.add("a");//向集合添加元素
		set.add("b");//向集合添加元素
		Iterator<String> it = set.iterator();//创建迭代器
		while (it.hasNext()) {//遍历HashSet集合
			String str= (String) it.next();//获取集合中元素
			System.out.println(str);
		}
	}
}

  

        从上面的运行结果可以看出,遍历出的Set集合中只有3个元素,而代码中通过add方法添加了c、c、a和b4个元素,造成这种结果的原因是Set集合中不允许有重复元素,而添加的4个元素中有两个相同的c,所以编译器默认只添加了一个c元素,另外一个并没有执行添加操作。 

10.4.3 TreeSet的两种排序方法 

  一、引入排序

@Test
	public void test1() {
		TreeSet treeSet = new TreeSet();
		treeSet.add(10);
		treeSet.add(11);
		treeSet.add(13);
		treeSet.add(12);
		for (Object object : treeSet) {
			System.out.print(object + " " );
		}	
	}

运行结果:10 11 12 13

结论:默认进行升序排列

思考:但是对于自定义对象呢?

   /*  
        实体类:Book
    */
    public class Book { 
    	private Integer bookId;
	private String bookName;
	private String bookAuthor;
	private Double price;
    }
   /*  
        测试类
    */
     @Test
     public void test2() {
		
	Book book1 = new Book(1, "红楼梦", "曹雪芹",11.0);
	Book book2 = new Book(2, "西游记", "曹雪芹",13.0);
	Book book3 = new Book(3, "水浒传", "曹雪芹",12.0);
	TreeSet treeSet = new TreeSet();
	treeSet.add(book1);
	treeSet.add(book2);
	treeSet.add(book3);
	for (Object object : treeSet) {
		Book book = (Book)object;
		System.out.println(book.getBookName() + book.getPrice());
	   }
	}

运行结果:

解决方案:1、自然排序 2、定制排序

二、自定义类型排序

如果集合存储的是自定义类型,当存入自定义的引用类型的时候就必须考虑到元素要求具有可排序性,不然会引发ClassCastException异常,所以要对自定义类型进行处理,必须要实现 Comparable或Compared接口。当把一个对象加入TreeSet集合中时,TreeSet调用该对象的compareTo(Object obj)方法与容器中的其他对象比较大小,然后根据红黑树算法决定它的存储位置。

2.1 自然排序

TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间大小关系,然后将集合元素按升序排列,这种方式就是自然排序。(比较的前提:两个对象的类型相同)。

操作步骤:

1、Book类实现Comparable接口;

2、重写Comparable接口中的compareTo方法。

  /*
      Book类
      compareTo(T o) : 比较此对象与指定对象的顺序。
      特别注意在重写Compareto方法时,注意排序 !!!
  */ 
   public class Book implements Comparable{ // 第一步:实现Comparable接口
    	private Integer bookId;
	private String bookName;
	private String bookAuthor;
	private Double price;
        public int compareTo(Object o) {    // 第二步:重写Comparable接口中的compareTo方法。
                // 若想按照价格从小到大排序,则需要return  = 1 ,即已存在数据大于待存数据
		Book book = (Book)o;
	        int flag = (int)(this.getPrice() - book.getPrice()); 
		return flag;
 	}
    }
   /*
       测试类
   */
    @Test
    public void test3() {
	Book book1 = new Book(1, "红楼梦", "曹雪芹",11.0);
	Book book2 = new Book(2, "西游记", "曹雪芹",13.0);
	Book book3 = new Book(3, "水浒传", "曹雪芹",12.0);
	TreeSet treeSet = new TreeSet();
	treeSet.add(book1);
	treeSet.add(book2);
	treeSet.add(book3);
	for (Object object : treeSet) {
		Book book = (Book)object;
		System.out.println(book.getBookName() + book.getPrice());
	}	
}

运行结果:

2.2 定制排序

TreeSet的自然排序是根据集合元素的大小,TreeSet将他们以升序排列。如果需要实现定制排序,例如降序,则可以使用Comparator接口。该接口里包含一个int compare(T o1, T o2)方法,该方法用于比较o1和o2的大小。如果需要实现定制排序,则需要在创建TreeSet集合对象时,并提供一个Comparator对象与该TreeSet集合关联,由该Comparator对象负责集合元素的排序逻辑。

操作步骤:

让集合构造方法接收Comparator的实现类的compare()方法。

   /*  
        实体类:Book
    */
    public class Book { 
    	private Integer bookId;
	private String bookName;
	private String bookAuthor;
	private Double price;
    }
   /** 
       测试类
   */
   @Test
   public void test4() {
	Book book1 = new Book(1, "红楼梦", "曹雪芹",11.0);
	Book book2 = new Book(1, "西游记", "曹雪芹",3.0);
	Book book3 = new Book(1, "水浒传", "曹雪芹",12.0);
	/**
           compare有两个参数,o1和o2,如果
	   o1 < o2  返回负数,
	   o1 = o2  返回正数,
           o1 > o2 返回正数。
        */
	TreeSet treeSet = new TreeSet(new Comparator() {   // 匿名内部类操作
	public int compare(Object o1, Object o2) {	
               Book book1 = (Book)o1;
               Book book2 = (Book)o2;			
	       return (int)( book1.getPrice() - book2.getPrice());				
		}	
	});
		treeSet.add(book1);
		treeSet.add(book2);
		treeSet.add(book3);
		for (Object object : treeSet) {
			Book book = (Book)object;
			System.out.println(book.getBookName() + book.getPrice());
		}
	}
   

运行结果:

10.5 Map集合

        在现实生活中,每辆车都有唯一的车牌号,通过车牌号可以查询到这辆车的详细信息,这两者是一对一的关系,在应用程序中,如果想存储这种具有对应关系的数据,则需要使用JDK中提供的Map接口。Map接口没有继承Collection接口,其提供的是key到value的映射。Map 中不能包含相同的key,每个key只能映射一一个value,另外,key还决定了存储对象在映射中的存储位置,但不是由key对象本身决定的,而是通过一种 “ 散列技术”进行处理,产生一个散列码的整数值来确定存储对象在映射中的存储位置。Map集合包括Map接口以及Map接口的所有实现类。

10.5.1 Map接口

        Map按口提供了将key映射到值的对象。一个映射不能包含重复的key,每个key最多只能映射个值。

返回

功能描述

Put(object key,object value)

向集合中添加指定的key与value的映射关系

Containskey(object key)

如果此映射包含指定key的映射关系,则返回true

Containsvalue(object value)

如果此映射将一个或多个key映射到指定值,则返回true

Get(object key)

如果存在指定的key对象,则返回该对象对应的值,否则返回null

Keyset()

返回该集合中的所有key对象形成的set集合

Values()

返回该集合中所有值对象形成的collection集合

10.5.2 接口的实现类

        Map接口常用的实现类有HashMap和TreeMap两种,分别如下。

        (1) HashMap类是基于哈希表的Map接口的实现,此实现提供所有可选的映射操作,并允许使用null值和null键,但必须保证键的唯-性。HashMap通过哈希表对其内部的映射关系进行快速查找。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

        (2) TreeMap类不仅实现了Map接口,还实现了java.util.SortedMap接口,因此,集合中的映射关系具有一定的顺序。但在添加、删除和定位映射关系时,TreeMap 类比HashMap类性能稍差.由于TreeMap类实现的Map集合中的映射关系是根据键对象按照定的顺序排列的, 因此不允许键对象是null。

        在项目中创建类HashMapTest,在主方法中创建Map集合,并向Map集合中添加键值对:然后分别获取Map集合中的所有key对象集合和所有values值集合,并输出。

import java.util.*;//导入要用到的包
public class HashMapTest {
	public static void main(String[] args) {
		Map<String, String> map = new HashMap<>(); // 创建Map实例
		map.put("ISBN-978654", "Java从入门到精通"); // 向集合中添加对象
		map.put("ISBN-978361", "Android从入门到精通");// 向集合中添加对象
		map.put("ISBN-978893", "21天学Android");// 向集合中添加对象
		map.put("ISBN-978756", "21天学Java");// 向集合中添加对象
		Set<String> set = map.keySet(); // 构建Map集合中所有key对象的集合
		Iterator<String> it = set.iterator(); // 创建集合迭代器
		System.out.println("key值:");
		while (it.hasNext()) { // 遍历集合
			System.out.print(it.next()+"\t");
		}
		Collection<String> coll = map.values(); // 构建Map集合中所有values值集合
		it = coll.iterator();
		System.out.println("\nvalues值:");
		while (it.hasNext()) { // 遍历集合
			System.out.print(it.next()+"\t");
		}
	}
}

说明:Map集合中允许值对象是Null,而且没有个数限制。例如:可通过map.put("05",null);语句向集合中添加对象。 

10.6 集合的使用场所

        前面介绍了java中最常见的3种集合: List集合、Set集合和Map集合,那么在实际开发中,具体何时应该选择哪种集合呢?这里我们总结了以下原则。

        (1) List集合关注的是索引,其元素是顺序存放的,例如一个班的学生成绩,成绩可以重复,就可以使用List集合存取。

        (2) Set集合关注唯一性,它的值不允许重复,例如每个班的学生的学号,每个学生的学号是不能重复的。

        (3) Map集合关注的是唯一的标识符(KEY),它将唯一的键映射到某个元素,例如每个班学生的学号与姓名的映射,每个学号对应一个学生的姓名,学号是不能重复的,但是学生的姓名有可能重复。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值