一、认识集合
(1)开发应用程序时,如果想存储多个同类型的数据,可以使用数组来实现;但是使用数组存在如下一些明显缺陷:
-->数组长度固定,不能很好地适应元素数量动态变化的情况。
-->可通过数组名.length获取数组的长度,却无法直接获取数组中实际存储的元素个数。
-->数组采用在内存中分配连续空间的存储方式存储,根据元素信息查找时效率比较低,需要多次比较。
(2)从以上分析可以看出数组在处理一些问题时存在明显的缺陷,针对数组的缺陷,Java提供了比数组更灵活、更实用的集合框架,可大大提高软件的开发效率,并且不同的集合可适用于不同应用场合。
(3)Java集合框架提供了一套性能优良、使用方便的接口和类,它们都位于java.util包中,其主要内容及彼此之间的关系如下图所示。
(4)从上图可以看出,Java的集合类主要由Map接口和Collection接口派生而来,其中Collection接口有两个常用的子接口,即List接口和Set接口,所以通常说Java集合框架由3大类接口组成(Map接口、List接口和Set接口)。
二、List接口
~ Collection接口是最基本的集合接口,可以存储一组不唯一、无序的对象。
~ List接口继承自Collection接口,是有序集合。用户可以使用索引(下标)访问List接口中的元素,类似于数组。
~ List接口中允许存放重复元素,也就是说List可以存放一组不唯一、有序的对象。
~ List接口常用的实现类有ArrayList和LinkedList。
1、 使用ArrayList类动态存储数据
(1)针对数组的一些缺陷,Java集合框架提供了ArrayList集合类,对数组进行了封装,实现了长度可变的数组,而且和数组采用相同的存储方式,在内存中分配连续的空间,如下图所示,所以,经常说ArrayList为动态数组。
但是它不等同于数组,ArrayList集合中可以添加任何类型的数据,并且添加的数据都将转换成Object类型,而在数组中只能添加同一类型的数据。
//创建3个NewsTitle类对象 NewsTitle nt1 = new NewsTitle(1001, "新闻一", "作者1"); NewsTitle nt2 = new NewsTitle(1002, "新闻二", "作者2"); NewsTitle nt3 = new NewsTitle(1003, "新闻三", "作者3"); //数据准备好了,接下来要准备一个集合容器,使用ArrayList ArrayList al = new ArrayList();
(2)ArrayList类提供了很多方法用于操作数据,下表列出的是ArrayList类的常用方法。
各方法具体用法代码展示:
//将数据存储到集合中,使用ArrayList类中的add()方法将数据存储到集合中 al.add(nt1); al.add(nt2); al.add(nt3); al.add(nt2); //讲数据存储到集合中的指定位置:add(int index,Object obj) al.add(2, nt1); //接下来对集合中元素的操作,都是通过集合对象名al调用方法来实现 //1)获取集合中的元素个数:size() int size =al.size(); System.out.println("al集合中元素个数:"+size); //2)获取集合中某个指定下标的元素:get(int index) //获取集合中的第一个元素 /* * 在NewsTitle类没有重写toString()方法的时候,通过al.get()方法获取集合中元素,直接输出这个元素,得到的是一个地址值 * 因为直接输出对象和通过对象调用toString(),这个toString()是Object类中的toString()方法,输出的都是地址值 * 输出地址没有任何意义,所以会在NewsTitle类中重写toString()方法 * * 因为在NewsTitle类中重写了toString()方法,通过al.get()方法获取集合中的元素,虽然得到的类型是Object类型 * 但是在输出对象的时候,调用的是NewsTitle类重写后的toString(); */ Object obj1 =al.get(0); //System.out.println(obj1); NewsTitle nt = (NewsTitle)obj1; System.out.println(nt); System.out.println("---------------------------"); //3)遍历集合中的元素 for(int i =0;i Object object=al.get(i); NewsTitle newsTitle = (NewsTitle)object; System.out.println(newsTitle); } //4)判断集合中是否包含某一个元素:contains() boolean result1 = al.contains(nt3); System.out.println("集合中包含nt3这个元素:"+result1); //5)删除集合中的元素:remove(元素名)/remove(元素下标) boolean result2 =al.remove(nt3); System.out.println("元素删除成功:"+result2); System.out.println("****************************************"); //删除后使用增强for循环遍历集合 for(Object object:al){ NewsTitle newsTitle = (NewsTitle)object; System.out.println(newsTitle); } System.out.println("****************************************"); Object obj=al.remove(1); System.out.println(obj); System.out.println("****************************************"); //删除元素后使用迭代器遍历集合:iterator() /* * Iterator:迭代器,可以将它看成是集合容器 * 将集合al中得元素转移到了Iterator中 * 接下来使用hasNext()方法判断Iterator容器中是否有元素,如果有返回true,那么就调用next()方法取出集合中的元素 * 如果hasNext()方法返回false,说明Iterator容器中没哟元素 * * */ Iterator it =al.iterator(); //从it容器中取出元素 while(it.hasNext()){ Object object =it.next(); NewsTitle ntt = (NewsTitle)object; System.out.println(ntt); } //判断集合是否为空:isEmpty() boolean result3 =al.isEmpty(); System.out.println("集合为空:"+result3); System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); //将集合中的元素转换为数组:toArray() Object[] objs=al.toArray(); for (int i = 0; i < objs.length; i++) { System.out.println(objs[i]); } //清空集合:clear() al.clear(); System.out.println(al.size()); System.out.println(al.isEmpty());
(3)ArrayList集合因为可以使用索引来直接获取元素,所以其优点是遍历元素和随机访问元素的效率比较高。但是由于ArrayList集合采用了和数组相同的存储方式,在内存中分配连续的空间,因此在添加和删除非尾部元素时会导致后面所有元素的移动,这就造成在插入元素、删除元素等操作频繁的应用场景下使用ArrayList会导致性能低下。所以数据操作频繁时,最好使用LinkedList存储数据。
2、 使用LinkedList类动态存储数据
(1)LinkedList类是List接口的链接列表实现类。它支持实现所有List接口可选的的列表的操作,并且允许元素值是任何数据,包括null。
(2)LinkedList类采用链表存储方式存储数据,如下图所示,优点在于插入、删除元素时效率比较高,但是LinkedList类的查找效率很低。
(3)它除了包含ArrayList类所包含的方法之外,还提供了下表所示的一些方法,可以在LinkedList类的首部或尾部进行插入、删除操作。
//获取集合中的第一个元素 Object obj2=linkList.getFirst(); NewsTitle ntt2 = (NewsTitle)obj2; System.out.println(ntt2); //获取集合中的最后一个元素 Object obj3=linkList.getLast(); NewsTitle ntt3 = (NewsTitle)obj3; System.out.println(ntt3); //删除集合中的第一个元素和最后一个元素 System.out.println("删除的第一个元素是:"+linkList.removeFirst()); System.out.println("删除的最后一个元素是:"+linkList.removeLast()); System.out.println("集合为空:"+linkList.isEmpty()); linkList.clear(); System.out.println("集合为空:"+linkList.isEmpty());
(4)除了LinkedList类中特有的方法外,LinkedList类和ArrayList类所包含的大部分方法是完全一样的,这主要是因为它们都是List接口的实现类。由于ArrayList采用和数组一样的连续的顺序存储方式,当对数据频繁检索时效率较高,而LinkedList类采用链表存储方式,当对数据添加、删除或修改比较多时,建议选择LinkedList类存储数据。
三、Set接口
1、 Set接口概述
(1)Set接口是Collection接口的另外一个常用子接口,Set接口描述的是一种比较简单的集合。
(2)集合中的对象并不按特定的方式排序,并且不能保存重复的对象,也就是说Set接口可以存储一组唯一、无序的对象。
(3)Set接口常用的实现类有HashSet。
2、 使用HashSet类动态存储数据
(1)HashSet集合的特点如下:
-->集合内的元素是无序排列的。
-->HashSet类是非线程安全的。
-->允许集合元素值为null。
(2)HashSet类的常用方法如下所示:
(3)List接口可以使用for循环、增强for循环、迭代器(Iterator接口)三种方式遍历。使用for循环遍历时,通过get()方法取出每个对象,但HashSet类不存在get()方法,所以Set接口无法使用普通for循环遍历。
(4)Set接口可以使用增强for循环、迭代器(Iterator接口)两种方式遍历。
代码展示:
package cn.bdqn.demo03; import java.util.HashSet; import java.util.Iterator; import cn.bdqn.demo02.NewsTitle; public class HashSetDemo01 { public static void main(String[] args) { // 创建3个NewsTitle类对象 NewsTitle nt1 = new NewsTitle(1001, "新闻1","作者1"); NewsTitle nt2 = new NewsTitle(1002, "新闻2","作者2"); NewsTitle nt3 = new NewsTitle(1003, "新闻3","作者3"); // 数据准备好了,接下来要准备一个集合容器,使用 HashSet hs = new HashSet(); //将元素存储到集合中 hs.add(nt1); hs.add(nt2); hs.add(nt3); hs.add(nt2); //获取集合中元素个数 int size = hs.size(); System.out.println("集合元素个数:"+size); //获取集合中的元素,Set集合是无序的,所以里面没有get(下标)方法获取元素 for(Object object:hs){ NewsTitle newsTitle = (NewsTitle)object; System.out.println(newsTitle); } System.out.println("--------------------使用迭代器遍历集合----------------"); //可以通过迭代器来遍历元素 Iterator it =hs.iterator(); while(it.hasNext()){ Object object = it.next(); NewsTitle newsTitle = (NewsTitle)object; System.out.println(newsTitle); } } }
四、Iterator接口
1、 Iterator接口概述
(1)Iterator接口表示对集合进行迭代的迭代器。Iterator接口为集合而生,专门实现集合的遍历。
(2)凡是由于Collection接口派生而来的接口或者类,都实现了iterator()方法,iterator()方法返回一个Iterator对象。
(3)Iterator接口主要有如下两个方法:
-->hasNext():判断是否存在在一个可访问的元素,如果仍有元素可以迭代,则返回true。
-->next():返回要访问的下一个元素。
2、 使用Iterator遍历集合
Iterator it = list.iterator(); //获取集合迭代器Iterator while(it.hashNext()){ //通过迭代器依次输出集合中所有元素的信息 Object obj = it.next(); }
五、Map接口
1、 Map接口概述
(1)Map接口存储一组成对的键(key)——值(value)对象,提供key到value的映射,通过key来检索。
(2)Map接口中的key不要求有序,不允许重复。value同样不要求有序,但允许重复。
(3)Map接口的常用方法如下:
2、使用HashMap类动态存储数据
(1)Map接口中存储的数据都是键——值对,最常用的Map的实现类是HashMap,其优点是查询元素效率高。
(2)遍历HashMap集合时可以遍历键集和值集,有for循环遍历、增强for循环遍历和迭代器(Iterator接口)遍历三种方式。
代码展示:
(3)map集合的第3种遍历方式:map.entrySet()方法
//map集合的第3种遍历方式 Set keyValues=map.entrySet(); for(Object obje:keyValues){ Map.Entry me =(Map.Entry)obje; //获取键 Object ob1 = me.getKey(); String key = (String)ob1; //获取值 Object ob2 =me.getValue(); Student student = (Student)ob2; System.out.println(key+"对应的学生:"+student); }