一、引入集合的原因:
集合、数组都是对数据存储的实现,简称JAVA容器,在之前的学习中我们一直使用数组,数组的特点:
1.一旦初始化,其长度便就确定了;
2.数组只能操作指定类型的数组即我们使用时定义的数组;
3.数组所能提供的方法非常有限,对于删除、插入元素不太方便;
4.数组的元素是有序的、可重复的,对于无序、不可重复的需求难以实现。
二、集合概述
JAVA集合可分为Collection和Map两种体系:
Collection接口:单列数据,定义了存取一组对象方法的集合
List:元素有序、可重复的集合(动态数组)
Set:元素无序、不可重复的集合(类似于数学中的集合)
Map接口:双列数据,保存具有映射关系“Key—Value”的集合(类似于数学中的函数法f(x))
Collection接口是Set、List、Queue的父接口,该接口中定义的方法,既可以操作Set集合,也可以操作ListheQueue集合。
三、Collection接口
Collection的接口方法有:
1 、添加
add(Object obj)
addAll(Collection coll)
2 、获取有效元素的个数
int size()
3 、清空集合
void clear()
4 、是否是空集合
boolean isEmpty()
5 、是否包含某个元素
boolean contains(Object obj) : 是通过元素的 equals 方法来判断是否
是同一个对象
boolean containsAll(Collection c) : 也是调用元素的 equals 方法来比
较的。拿两个集合的元素挨个比较。
6、删除
boolean remove(Object obj) : 通过元素的 equals 方法判断是否是
要删除的那个元素。只会删除找到的第一个元素
boolean removeAll(Collection coll) : 取当前集合的差集
7 、取两个集合的交集
boolean retainAll(Collection c) : 把交集的结果存在当前集合中,不
影响 c
8 、集合是否相等
boolean equals(Object obj)
9 、转成对象数组
Object[] toArray()
10 、获取集合对象的哈希值
hashCode()
11 、遍历
iterator() : 返回迭代器对象,用于集合遍历
四、iterator迭代器接口
iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。
集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合 的第一个元素之前。
五、Collection的子接口
1.List接口
鉴于Java数组存储元素的局限性,我们常用List代替数组
List存储的特点是无序、可重复的,且每个元素都有与之对应的顺序索引。
List的常用实现类有:ArrayList、LinkList、Vector。
List 除了从 Collection 集合继承的方法外, List 集合里添加了一些根据索引来
操作集合元素的方法。
void add(int index, Object ele): 在 index 位置插入 ele 元素
boolean addAll(int index, Collection eles): 从 index 位置开始将 eles 中 的所有元素添加进来
Object get(int index): 获取指定 index 位置的元素
int indexOf(Object obj): 返回 obj 在集合中首次出现的位置
int lastIndexOf(Object obj): 返回 obj 在当前集合中末次出现的位置
Object remove(int index): 移除指定 index 位置的元素,并返回此元素
Object set(int index, Object ele): 设置指定 index 位置的元素为 ele
List subList(int fromIndex, int toIndex): 返回从 fromIndex 到 toIndex 位置的子集合
(1).ArrayList
ArrayList是List的主要实现类,本质上是对象引用了一个变长的数组。
(2).LinkedList
对于频繁进行插入和删除的操作,常采用LinkedList类。效率较高。
新增方法:
void addFirst(Object obj)
void addLast(Object obj)
Object getFirst()
Object getLast()
Object removeFirst()
Object removeLast()
LinkedList : 双向链表 ,内部没有声明数组,而是定义了 Node 类型的 first 和 last ,
用于记录首末元素。同时,定义内部类 Node ,作为 LinkedList 中保存数据的基
本结构。 Node 除了保存数据,还定义了两个变量:
prev 变量记录前一个元素的位置
next 变量记录下一个元素的位置
(3).Vector
Vector 是一个古老的集合,JDK1.0就有了。大多数操作与ArrayList 相同,区别之处在于 Vector 是线程安全的。
在各种 list 中,最好把 ArrayList 作为缺省选择。当插入、删除频繁时,使用LinkedList ; Vector 总是比 ArrayList 慢,所以尽量避免使用。
新增方法:
void addElement(Object obj)
void insertElementAt(Object obj,int index)
void setElementAt(Object obj,int index)
void removeElement(Object obj)
void removeAllElements()
2.Set接口
Set接口也是Collection的子接口,但Set接口并没有提供额外的方法。
Set集合中的元素是无序、不可重复的。当添加Set集合中已有的元素时,就会添加失败。
在判断元素相等时,使用的是equles()。
(1)HashSet
HashSet是Set接口的典型实现类,HashSet是按照Hash方法存储元素的,具有较好的存取、查找和删除性能。
HashSet存储元素的特点:
不是线程安全的,可以存放null,不能保证元素的排列顺序。
HashSet 集合判断两个元素相等的标准 : 两个对象通过 hashCode() 方法比较相
等,并且两个对象的 equals() 方法返回值也相等。
对于存放在 Set 容器中的对象, 对应的类一定要重写 equals() 和 hashCode(Object
obj) 方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”。
(2)LInkedHashSet
LinkedHanhSet是HashSet的子类,
LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置, 但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
LinkedHashSet 不允许集合元素重复。
(3)TreeSet
TreeSet 是 SortedSet 接口的实现类, TreeSet 可以确保集合元素处于排序状态。
TreeSet 底层使用 红黑树 结构存储数据
新增的方法如下: ( 了解 )
Comparator comparator()
Object first()
Object last()
Object lower(Object e)
Object higher(Object e)
SortedSet subSet(fromElement, toElement)
SortedSet headSet(toElement)
SortedSet tailSet(fromElement)
TreeSet 两种排序方法: 自然排序 和 定制排序 。默认情况下, TreeSet 采用自然排序
练习:在 List 内去除重复数字值,要求尽量简单
@Test /** * 练习:在List内去除重复数字值,要求尽量简单 */ public void test1(){ LinkedList<Object> list= new LinkedList<>(); list.add("123"); list.add(12); list.add('i'); list.add(12); LinkedList<Object> list1=new LinkedList<>(); list1= (LinkedList<Object>) delete(list); System.out.println(list1); } public Collection delete(LinkedList list){ HashSet set = new HashSet(); set.addAll(list); return new LinkedList(set); }
2.Map接口
Map接口是双列数据集合,用于保存具有映射关系的数据:Key-Value;
Map 中的 key 和 value 都可以是任何引用类型的数据
Map 中的 key 用 Set 来存放, 不允许重复 ,即同一个 Map 对象所对应 的类,须重写hashCode() 和 equals() 方法
常用 String 类作为 Map 的“键”
key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到 唯一的、确定的 value
Map 接口的常用实现类: HashMap 、 TreeMap 、 LinkedHashMap 和Properties 。其中, HashMap 是 Map 接口使用频率最高的实现类
添加、删除、修改操作:
Object put(Object key,Object value) :将指定 key-value 添加到 ( 或修改 ) 当前 map 对象中
void putAll(Map m): 将 m 中的所有 key-value 对存放到当前 map 中
Object remove(Object key) :移除指定 key 的 key-value 对,并返回 value
void clear() :清空当前 map 中的所有数据
元素查询的操作:
Object get(Object key) :获取指定 key 对应的 value
boolean containsKey(Object key) :是否包含指定的 key
boolean containsValue(Object value) :是否包含指定的 value
int size() :返回 map 中 key-value 对的个数
boolean isEmpty() :判断当前 map 是否为空
boolean equals(Object obj) :判断当前 map 和参数对象 obj 是否相等
元视图操作的方法:
Set keySet() :返回所有 key 构成的 Set 集合
Collection values() :返回所有 value 构成的 Collection 集合
Set entrySet() :返回所有 key-value 对构成的 Set 集合
(1).HashMap
HashMap 是 Map 接口 使用频率最高 的实现类。
允许使用 null 键和 null 值,与 HashSet 一样,不保证映射的顺序。
所有的 key 构成的集合是 Set: 无序的、不可重复的。所以, key 所在的类要重写:equals()和 hashCode()
所有的 value 构成的集合是 Collection: 无序的、可以重复的。所以, value 所在的类要重写equals()
一个 key-value 构成一个 entry
所有的 entry 构成的集合是 Set: 无序的、不可重复的
HashMap 判断两个 key 相等的标准 是:两个 key 通过 equals() 方法返回 true, hashCode 值也相等。
HashMap 判断两个 value 相等的标准 是:两个 value 通过 equals() 方法返回 true 。
(2).LinkedHashMap
LinkedHashMap 是 HashMap 的子类
在 HashMap 存储结构的基础上,使用了一对双向链表来记录添加元素的顺序
与 LinkedHashSet 类似, LinkedHashMap 可以维护 Map 的迭代顺序:迭代顺序与 Key-Value 对的插入顺序一致
(3)TreeMap
TreeMap 存储 Key-Value 对时,需要根据 key-value 对进行排序。
TreeMap 可以保证所有的 Key-Value 对处于 有序 状态。
TreeSet 底层使用 红黑树 结构存储数据
TreeMap 的 Key 的排序:
自然排序 : TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
定制排序 :创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现
Comparable 接口
TreeMap 判断 两个 key 相等的标准 :两个 key 通过 compareTo() 方法或者 compare() 方法返回 0 。
4)HashTable
Hashtable 是个古老的 Map 实现类, JDK1.0 就提供了。不同于 HashMap ,
Hashtable 是线程安全的。
Hashtable 实现原理和 HashMap 相同,功能相同。底层都使用哈希表结构,查询
速度快,很多情况下可以互用。
与 HashMap 不同, Hashtable 不允许使用 null 作为 key 和 value
与 HashMap 一样, Hashtable 也不能保证其中Key-Value 对的顺序
Hashtable 判断两个 key 相等、两个 value 相等的标准,与 HashMap 一致。
(5)Properties
Properties 类是 Hashtable 的子类,该对象用于处理属性文件
由于属性文件里的 key 、 value 都是字符串类型,所以 Properties 里的 key
和 value 都是字符串类型
存取数据时,建议使用 setProperty(String key,String value) 方法和
getProperty(String key) 方法
Properties pros = new Properties();
pros .load( new FileInputStream( "jdbc.properties" ));
String user = pros .getProperty( "user" );
System. out .println( user );
六、Collections工具类
Collections 是一个操作 Set 、 List 和 Map 等集合的工具类
Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
排序操作 : (均为 static 方法)
reverse(List) : 反转 List 中元素的顺序
shuffle(List) : 对 List 集合元素进行随机排序
sort(List) : 根据元素的自然顺序对指定 List 集合元素按升序排序
sort(List , Comparator) : 根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
swap(List , int , int) : 将指定 list 集合中的 i 处元素和 j 处元素进行交换
Collections 是一个操作 Set 、 List 和 Map 等集合的工具类
Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
排序操作 : (均为 static 方法)
reverse(List) : 反转 List 中元素的顺序
shuffle(List) : 对 List 集合元素进行随机排序
sort(List) : 根据元素的自然顺序对指定 List 集合元素按升序排序
sort(List , Comparator) : 根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
swap(List , int , int) : 将指定 list 集合中的 i 处元素和 j 处元素进行交换
七、练习
1. 请从键盘随机输入 10 个整数保存到 List 中,并按倒序、从大到小的顺序显示出来
@Test /** * 1.请从键盘随机输入10个整数保存到List中,并按倒序、从大 * 到小的顺序显示出来 */ public void test2(){ Scanner sc = new Scanner(System.in); System.out.println("请输入10个整数:"); List list = new ArrayList(); for (int j = 0; j < 10; j++) { int i = sc.nextInt(); list.add(i); } System.out.println("按照倒序的顺序显式:"); Iterator iterator = list.iterator(); Collections.reverse(list);// while (iterator.hasNext()) { System.out.println(iterator.next()); } System.out.println("按照从大到小输出"); Iterator iterator1=list.iterator(); Collections.sort(list); Collections.reverse(list); while(iterator1.hasNext()){ System.out.println(iterator.next()); } }
2. 请把学生名与考试分数录入到集合中,并按分数显示前三名成绩学员的名字。
class Student implements Comparable<Student>{ private int score; private String name; public Student(int score, String name) { this.score = score; this.name = name; } public Student() { } public int getScore() { return score; } public void setScore(int score) { this.score = score; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "score=" + score + ", name='" + name + '\'' + '}'; } @Override public int compareTo(Student o) { if(this.getScore ()>o.getScore ()){ return 1; }else if(this.getScore ()==o.getScore ()){ return 0; }else{ return -1; } } } public class StudentsTest { public static void main(String[] args) { Student s1 = new Student (90, "琼文"); Student s2 = new Student (89, "莫兰"); Student s3= new Student (98, "泽文"); Student s4 = new Student (76, "宇华"); TreeSet<Student> set = new TreeSet<> ( ); set.add (s1); set.add(s2); set.add(s3); set.add(s4); Iterator<Student> iterator = set.iterator ( ); int i=0; while(i<3&&iterator.hasNext ()){ System.out.println (iterator.next ( ).getName ()); i++; } } }