前言
本小节为Java入门阶段最后一个小节,讲解总结了有关Java集合框架的知识。其中的图来自慕课网学习截图。
Java中的集合框架详解
- 集合框架的概念与作用
· Java中的集合类是一种工具类,就像是容器,存储任意数量的具有共同属性的对象。
· 集合的作用
1)在类的内部,对数据进行组织
2)简单而快速的搜索大数量的条目
3)有的集合接口,提供了一系列排列有序的元素,并且可以在序列中间快速的插入或者删除有关元素。
4)有的集合接口,提供了映射关系,可以通过关键字(key)去快速查找到对应的唯一对象,而这个关键字可以是任意类型。
· 与数组的比较
1)数组的长度是固定的,而集合的长度是可变的,伸缩性更好
2)数组只能通过下标访问元素,类型固定,而有的集合可以通过任意类型查找所映射的具体对象。 - 集合框架的体系结构
· Java的集合框架主要是为“Collection”和“Map”两大部分组成的。Collection和Map是Java集合框架的两个根接口。
· Collection旗下有三个子接口,分别是“List(序列)”、“Queue(队列)”和“Set(集)”。其中“List”和“Queue”存储的元素是排列有序的,并且是可以重复的。而“Set”中的元素是无序,并且是不可重复的。“List”和“Set”比较常用。
· “List”旗下有个很重要的实现类——“ArrayList(数组序列)”;“Queue”旗下有个很重要的实现类——“LinkedList(链表)”,链表同时也是List的实现类;“Set”旗下有个很重要的实现类——“HashSet(哈希集)”。
· “Map”最常用的是它的实现类,其中最重要的一个实现类为“HashMap(哈希表)”。
如下图所示:
- Collection接口、子接口以及实现类
· Collection接口是List、Set和Queue接口的父接口,定义了可用于操作List、Set和Queue的方法——增删改查。如下表所示:
其中常用方法如下:
- add(Object e):将一个对象当成Object类型添加进一个集合中。
- add(int index, Object element):将一个对象当成Object类型添加进一个集合中,其下标索引为index。
- get(int index):获取下标为‘index’的元素。
- addAll(Collection c):传递的参数为一个Collection的具体的实例,将其添加进一个集合中。
- addAll(int index, Collection c):传递的参数为一个Collection的具体的实例,将其添加进一个集合实例中,其下标索引为index。
- size():用于取得集合实例中元素的个数,即集合实例的长度的值。
- iterator():用于返回当前集合对象的迭代器。然后再通过这个迭代器去遍历当前集合中的每一个元素。迭代器本身也是一个‘Iterator’接口。‘Iterator’旗下有一个‘hasNext()方法’,如果它还有元素的话,则返回一个真值true;‘Iterator’旗下还有一个‘next()方法’用于取得具体的某个元素。迭代器只是用来遍历集合中元素的,它本身不具备任何存储元素的功能,即:迭代器是依赖于某个集合而存在的,本身并不能独立的存在。
- set(int index, Object element):index为索引位置的值,element为将要修改的新对象的值。可以通过调用set()方法来达到修改相应位置上元素的目的。
- remove(Object o):取得某个位置上的元素,并且把它传入到remove()方法中来实现删除的。
- remove(int index):传入指定的索引位置index,即可把索引位置index所对应的元素删除。该索引位置必须要在集合实例的长度范围之内,否则就会报数组下标越界异常。
- removeAll(Collection c):从某个集合中将另一个集合中的所有元素完全删除。即:从列表中移除指定collection中包含的其所有元素。
- contains(Object o):无论是List序列还是接下来要提到了Set集,都可以用它来判断集合中是否包含某个元素,返回值类型为布尔类型。
- containsAll(Collection<?> c):通过传递一个Collection类型的参数,从而判断集合中是否包含多个元素。
- indexOf(Object o):该方法用于取得某元素的索引位置。它的实现机制为:从序列第0个位置的元素开始,依次循环,并且调用每一个元素的equals()方法和参数对象进行比较,如果某一个equals()方法返回值为true,那么就把当前这个元素的索引位置作为结果返回。假如序列中有多个重复的元素,那么只返回这个重复的元素第一次出现时所在的下标索引位置。而如果equals()的参数对象在序列中均没有出现,则其返回值为-1。
- lastIndexOf(Object o):与上一个方法类似,但当序列中有多个重复的元素时,只返回这个重复的元素最后一次出现时所在的下标索引位置。而如果equals()的参数对象在序列中均没有出现,则其返回值为-1。
·遍历List序列的方式:
1)通过for循环遍历
2)通过迭代器遍历
3)通过for each循环遍历
· List接口及其实现类——ArrayList
1)List是元素有序并且可以重复的集合,被称为序列。
2)List可以精确的控制每个元素的插入位置,或删除某个位置元素。
3)ArrayList——数组序列,是List的一个重要实现类。
4)ArrayList底层是由数组实现的。
- 泛型(作用:用泛型规定一个集合的元素类型)
· 集合中的元素,可以是任意类型的对象(对象的引用)。如果把某个对象放入集合,则会忽略他的类型,而把它当做Object处理。
· 泛型则是规定了某个集合只可以存放特定类型的对象,会在编译期间进行类型检查,可以直接按指定类型获取集合元素。
· 泛型集合中,不能添加泛型规定的类型及其子类型以外的对象,否则会报错!
· 在泛型集合中,除了可以存入泛型类型的对象实例,还可以存入泛型的子类型的对象实例。
· 泛型集合中的限定类型,不能使用基本数据类型。但可以通过使用包装类限定允许存入的基本数据类型。 - Set接口及其实现类——HashSet
· Set是元素**无序并且不可以重复**的集合,被称为集。
·HashSet——哈希集
,是Set的一个重要实现类。
· 和List不同的是,Set并没有提供类似于‘Set()’的方法去修改某个位置上的元素。这是因为List序列是有序的,而Set集是无序的。所以不可能提供一个给定指定索引位置去修改相应位置上的元素的方法。
· 需要注意的一点是:循环遍历‘Set集’中的每一个元素只能用for each方法或iterator方法,而不能像List那样调用get()方法,因为Set本身是无序的,所以不可能去查询指定索引位置上的某个元素,只能用for each循环或iterator循环将其一个个迭代出来。而由于Set集是无序的,因此这个迭代出来的结果每一次都是不尽相同的。
· Set集中,添加某个对象,无论添加多少次,最终只会保留一个该对象(的引用),并且,保留的是第一次添加的那一个。
· Set集中是可以添加null对象的,只不过添加null对象对于实际应用没有太大的意义。
· 当我们在调用HashSet()的contains()方法的时候,系统是先调用每一个元素的hashCode()方法来返回哈希码,若哈希码的值相等的情况下,再调用equals()方法去判断是否相等。只有在这两个方法所返回的值都相等的情况下,才表明这个hashSet包含某一个元素。 - Map和HashMap
· Map接口
1)Map提供了一种映射关系,其中的元素是以键值对(key-value)的形式存储的,能够实现根据key快速查找value。
2)Map中的键值对以Entry类型的对象实例形式存在。
3)键(key值)不可重复,value值可以。
4)每个键最多只能映射到一个值。
5)Map接口提供了分别返回Key值集合、value值集合以及Entry(键值对)集合的方法。
6)Map支持泛型,形式如:Map<K, V>。
Map中定义的方法如下如所示:
其中常用方法如下:
- get(Object key):把key值作为参数传递进去,如果该映射关系存在,那么get()方法返回的就是key值这个键所对应的value值;如果该映射关系不存在,则返回一个空对象null值。
- put(Object key, Object value):通过向put()方法中传递一个key值和value值,即可将一个映射关系存储进Map表中。
- keySet():返回的是Map中所有键的Set集合。
- size():返回的是Map表的长度,或者说是容量。
- remove(Object key):通过把key值作为参数传递进去,将key值这个键所对应的映射关系(键值对)删除。
- entrySet():返回的是Map中的所有键值对的Entry类型的集合。因此需要用一个泛型为Entry的Set集合来接收。
- getKey():泛型为Entry的Set集合中的每一个实例对象的方法,用于返回当前键值对的key值。
- getValue():泛型为Entry的Set集合中的每一个实例对象的方法,用于返回当前键值对的value值。
- put(Object key, Object value):通过向put()方法中传递一个已经存在的key值和新的value值作为参数,来修改Map表中已经存在的映射关系。
- containsKey(Object key):用来判断Map表中是否包含某个Key值。
- containsValue(Object value):用来判断Map表中是否包含某个Value值。其与List序列中的contains()方法一样,其实现机制也是调用每一个Value值的equals()方法去和参数对象进行比较,如果匹配成功,那么返回结果为true。
· HashMap类
1)HashMap
是Map的一个重要实现类,也是最常用的,基于哈希表实现。
2)HashMap中的Entry对象是无序排列的。
3)Key值和Value值都可以为null,但是一个HashMap只能有一个key值为null的映射(key值不可重复)。
- Collections工具类:位于java.util中,即:
java.util.Collections类
。
· 既是Java集合框架中,用来操作集合对象的工具类,也是Java集合框架的成员。
· 其中定义了一个sort()(排序)方法
,如果我们想对List序列的实例化对象中的元素进行排序,就需要用到collections的sort()方法。 - Random类:属于Java标准类库中的类
· 由Random类实例化的对象可以生成很多随机数,其中包括很多随机整数。
· 其中有一个nextInt()方法
,用于生成随机的整数。 - Comparable接口
· 在Java中用Comparable接口
去表示某个对象是可以比较的。相当于给对象定义了一个默认的排序(比较)规则。
· 实现该接口表示:这个类的实例可以比较大小,可以进行自然排序。
· 定义了默认的比较规则。
· 其实现类需实现compareTo()方法
。
· compareTo()方法返回正数表示大,负数表示小,0表示相等。 - Comparator接口:用于定义临时比较规则的接口。
· 其实现类需要实现compare()方法
。
· Comparator和Comparable都是Java集合框架的成员。 - Java集合框架汇总如下图所示:
阶段性编程练习
目的:利用Collections.sort()方法对泛型为String的List进行排序
要求:
- 创建完List之后,往其中添加十条随机字符串
- 每条字符串的长度为10以内的随机整数
- 每条字符串的每个字符都为随机生成的字符,字符可以重复
- 每条随机字符串不可重复
核心源代码如下:
package com.collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class CollectionsTest {
/**
* 阶段性编程实战:利用Collections.sort()方法对泛型为String的List进行排序
* 要求: 1、创建完List<String>之后,往其中添加十条随机字符串
* 2、每条字符串的长度为10以内的随机整数
* 3、每条字符串的每个字符都为随机生成的字符,字符可以重复
* 4、每条随机字符串不可重复
*/
public void testSort(){
List<String> stringList = new ArrayList<String>();
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuffer sb;
// 该‘temp’变量用于将‘sb’变量从StringBuffer类型强制转换成String类型
String temp;
// 该for循环用于向List中添加十条随机字符串
for(int i = 0; i < 10; i++){
// 每一次循环, 对变量‘sb’做一次初始化操作
sb = new StringBuffer();
/**
* 这个do-while循环表明:如果stringList当中包括了随机生成的字符串sb
* 那么就需要再随机生成一个字符串,然后再去判断stringList中是否包含
* 这样就能确保stringList当中的元素都是不重复的
*/
do{
// 该‘length’变量用于存储每条字符串的随机长度(10以内)
int length = random.nextInt(10);
for(int j = 0; j < length; j++){
// 该‘number’变量作为str字符串的下标索引
int number = random.nextInt(62);
sb.append(str.charAt(number));
}
temp = sb.toString();
}while(stringList.contains(temp));
stringList.add(temp);
System.out.println("成功添加字符串:" + '\'' + temp + '\'');
}
System.out.println("------------排序前------------");
for (String string : stringList) {
System.out.println("元素:" + string);
}
Collections.sort(stringList);
System.out.println("------------排序后------------");
for (String string : stringList) {
System.out.println("元素:" + string);
}
}
/**
*
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
CollectionsTest ct = new CollectionsTest();
ct.testSort();
}
}
知识点补充(备注):
- 打印异常的处理信息的方法:e.printStackTrace();
- initCause()方法:为了当程序出现问题时能够检查真正的原因所在而对异常所进行的包装处理。
- 处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理。
- 在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常。
- 对于不确定的代码,也可以加上try-catch,处理潜在的异常。
- 尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出。
- 尽量添加finally语句块去释放占用的资源。
- 如果定义的成员变量没有初始化,在用System.out.println()输出时会报错。
// 例如:
int number = 0;
System.out.println("您输入的数字是" + number);
- Java中Scanner类中
next()方法
和nextLine()方法
的区别:
· next()方法遇见第一个有效字符(非空格,非换行符)时,开始扫描,当遇见第一个分隔符或结束符(空格或换行符)时,结束扫描,获取扫描到的内容,即获得第一个扫描到的不含空格、换行符的单个字符串。
· nextLine()方法可以扫描到一行内容并作为一个字符串而被获取到。 - 程序在调用
SimpleDateFormat对象的parse()方法
时可能会出现转换异常,即ParseException,因此需要进行异常处理。 - 程序在
使用Date类时需要导入java.util包
,使用SimpleDateFormat时需要导入java.text包
。 - 对象存入集合都变成Object类型,取出时需要进行强制类型转换。