目录
首先我们用一个案例来引出为什么我们要学习Java中的集合:
需求:利用数组存储3个学生信息,遍历数组获取每一个学生的信息
创建一个Studen类:
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
创建Student类测试类ObjectArrayDemo1:
//需求:利用数组存储3个学生信息,变量数组获取每一个学生的信息
public class ObjectArrayDemo1 {
public static void main(String[] args) {
Student[] arr = new Student[3];
for (int i =0 ; i < arr.length; i++){
System.out.println(arr[i]);
}
System.out.println("=======================================");
//创建3个学生对象
Student liudehua = new Student("刘德华", 18);
Student zhangxueyou = new Student("张学友", 19);
Student guofucheng = new Student("郭富城", 20);
//将创建好的3个学生对象,放到数组中
// for(int i=0;i<arr.length;i++){
// arr[i] = s1;
// }
/*
给对象数组赋值,使用循环是有问题的,
因为对象的名字没有规律,
没办法将每次循环依次赋值不一样的对象
*/
//所以给对象数组赋值,只能一个一个赋值
arr[0] = liudehua;
arr[1] = zhangxueyou;
arr[2] = guofucheng;
//遍历数组获取每一个学生对象
for (int i =0 ; i< arr.length;i++){
// System.out.println(arr[i]);
Student student = arr[i];
System.out.println(student.getName() + "---" + student.getAge());
}
}
}
输出结果:
null
null
null
=======================================
刘德华---18
张学友---19
郭富城---20
集合Interface Collection<E>
在Student这个例子中,假设在存储完所有的学生对象后,来了一个新同学A,也想放到对象数组中,直接放进去的话,长度已经是确定的,很明显没有空余的位置。 那么怎么办呢?创建一个新的数组,长度是原来数组长度+1,然后挨个存储。这个时候有一位学生B,提前毕业,数组中的元素就少了一个。但是呢,现在数组中就有一个空的位置,而这个空的位置依旧是占用内存的,也不太好,所以你又创建一个新的数组,长度-1,然后挨个存放。
上面的例子,无论是从增加还是删除,都非常麻烦,其实原则上我们修改是根据原先的东西基础上进行修改的。这个时候我们想到之前还学了一个容器,叫做StringBuffer,它就可以根据元素的多少来改变长度。但是,StringBuffer里面存储始终是一个一个的字符,而我们现在需要存放学生对象,所以用StingBuffer也不太合适。
那这里我们就想不到之前学过哪些容器,可以根据元素的多少改变长度。
Java替我们考虑到了这一点,根据存储的元素不同,元素的特点不同以及存储方式不同,提供了一个集合继承体系给我们:集合。
查看API文档我们知道:
这是JDK官方提供的Collection的继承关系图,有点乱我们改进一下。
Collection接口基本结构
Map接口基本结构
这时我们查看一下API是如何介绍Collection的:
public interface Collection<E> extends Iterable<E>集合层次结构中的根界面 。 集合表示一组被称为其元素的对象。 一些集合允许重复元素,而其他集合不允许。 有些被命令和其他无序。 JDK不提供此接口的任何直接实现:它提供了更具体的子接口的实现,如Set和List 。 该界面通常用于传递集合,并在需要最大的通用性的情况下对其进行操作。包或多重集 (可能包含重复元素的无序集合)应直接实现此接口。
所有通用的Collection实现类(通常通过其子接口间接实现88446144404803)应提供两个“标准”构造函数:一个void(无参数)构造函数,它创建一个空集合,以及一个构造函数, Collection ,它创建一个与其参数相同的元素的新集合。 实际上,后一个构造函数允许用户复制任何集合,生成所需实现类型的等效集合。 没有办法强制执行此约定(因为接口不能包含构造函数),而是所有Java平台库中的通用Collection实现。
包含在该界面中的“破坏性”的方法,即,修改其经营的收集方法,被指定抛出UnsupportedOperationException如果此collection不支持该操作。 如果是这样的话,可能会,但不要求这些方法,抛出一个UnsupportedOperationException如果调用会对收集没有影响。 例如,如果要添加的集合为空,则可以在不可修改的集合上调用addAll(Collection)方法,但不是必须抛出该异常。
Some collection implementations have restrictions on the elements that they may contain.例如,一些实现禁止空元素,有些对它们的元素的类型有限制。 尝试添加不合格元素会引发未经检查的异常,通常为NullPointerException或ClassCastException 。 尝试查询不合格元素的存在可能会引发异常,或者可能只是返回false; 一些实现将展现出前者的行为,一些实现将展现出后者。 更一般来说,尝试对不符合条件的元素进行操作,其完成不会导致将不合格元素插入到集合中可能会导致异常,或者可能会成功执行该选项。 此异常在此接口的规范中标记为“可选”。
每个集合决定自己的同步策略。 在没有实现的更强保证的情况下,未定义的行为可能是由于对由另一个线程进行突变的集合的任何方法的调用而导致的; 这包括直接调用,将集合传递给可能执行调用的方法,并使用现有的迭代器来检查集合。
在集合框架接口的许多方法在来定义equals方法。 例如,对于在本说明书contains(Object o)方法表示:“返回true当且仅当这个集合包含至少一个元素e使得(o==null ? e==null : o.equals(e))”。 该规范不应该被解释为意味着具有非空参数调用o Collection.contains会导致o.equals(e)被调用任何元素e。 实现可以自由地实现优化,从而避免equals调用,例如,首先比较两个元素的哈希码。 ( Object.hashCode()规范保证具有不等的哈希码的两个对象不能相等。)更一般地,各种Collections Framework接口的实现可以随意使用底层Object方法的指定行为,无论执行者认为合适。
执行递归遍历集合的一些集合操作可能会失败,而自引用实例的异常会导致集合直接或间接包含其自身。 这包括
clone()
,equals()
,hashCode()
和toString()
方法。 实现可以可选地处理自引用场景,然而大多数当前实现不这样做。此接口是成员Java Collections Framework 。
实现要求:
默认方法实现(继承或其他)不应用任何同步协议。 如果
Collection
实现具有特定的同步协议,那么它必须覆盖默认实现以应用该协议。
看完这么多东西确实是不方便理解,那么用我们话概述一下:
集合和数组的不同点:
- 数组的长度是不可变的,集合是可以改变的
- 数组可以存放同一种基本数据类型或者引用数据类型,而集合只能存放引用数据类型,并且集合中可以存放不同的引用数据类型。(我们虽然说了集合可以存放不同的引用类型,确实也可以这么做,但是开发中一个集合存放一种数据类型)。
- 集合可以存放各种各样的数据,每一种数据的长度,大小以及自身的特点都不一样。所以,java提供的集合也应该不能够是单一的,我们要针对不同的需求,java提供不同的集合类。这么多不同的集合,他们的底层数据结构也是不同的,不同并不重要,我们只要知道集合是可以用来存放东西的,不光可以存放,而且可以去使用这些东西,比如:查找获取,判断等。
既然可以上面的操作,这些不同的集合类应该有某种共性的内容,所以我们根据集合的共性内容不断地 向上提取,最终整体形成一个继承体系。
Collection:是集合中的顶层接口,它存在由它扩展开来的继承体系,为什么要分出很多不同的集合? 根据元素是否唯一,是否有序来区分这么多集合。
集合接口
每个接口的概述:
集合接口的作用
序号 | 接口描述 |
---|---|
1 | Collection 接口 Collection 是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素, Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。 Collection 接口存储一组不唯一,无序的对象。 |
2 | List 接口 List接口是一个有序的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的下标)来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素。 List 接口存储一组不唯一,有序(插入顺序)的对象。 |
3 | Set Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素。 Set 接口存储一组唯一,无序的对象。 |
4 | SortedSet 继承于Set保存有序的集合。 |
5 | Map Map 接口存储一组键值对象,提供key(键)到value(值)的映射。 |
6 | Map.Entry 描述在一个Map中的一个元素(键/值对)。是一个 Map 的内部接口。 |
7 | SortedMap 继承于 Map,使 Key 保持在升序排列。 |
8 | Enumeration 这是一个传统的接口和定义的方法,通过它可以枚举(一次获得一个)对象集合中的元素。这个传统接口已被迭代器取代。 |
Set和List的区别
-
1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
-
2. Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
-
3. List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变.
-
<实现类有ArrayList,LinkedList,Vector> 。
对于 Set、List、Queue 和 Map 这 4 种集合,Java 最常用的实现类分别是 HashSet、TreeSet、ArrayList、ArrayDueue、LinkedList 和 HashMap、TreeMap 等。表 2 介绍了集合中这些常用的实现类。
类名称 | 作用 |
---|---|
HashSet | 为优化査询速度而设计的 Set。它是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,实现比较简单 |
TreeSet | 实现了 Set 接口,是一个有序的 Set,这样就能从 Set 里面提取一个有序序列 |
ArrayList | 一个用数组实现的 List,能进行快速的随机访问,效率高而且实现了可变大小的数组 |
ArrayDueue | 是一个基于数组实现的双端队列,按“先进先出”的方式操作集合元素 |
LinkedList | 对顺序访问进行了优化,但随机访问的速度相对较慢。此外它还有 addFirst()、addLast()、getFirst()、getLast()、removeFirst() 和 removeLast() 等方法,能把它当成栈(Stack)或队列(Queue)来用 |
HsahMap | 按哈希算法来存取键对象 |
TreeMap | 可以对键对象进行排序 |
如何使用迭代器
通常情况下,你会希望遍历一个集合中的元素。例如,显示集合中的每个元素。
一般遍历数组都是采用for循环或者增强for,这两个方法也可以用在集合框架,但是还有一种方法是采用迭代器遍历集合框架,它是一个对象,实现了Iterator 接口或 ListIterator接口。
迭代器,使你能够通过循环来得到或删除集合的元素。ListIterator 继承了 Iterator,以允许双向遍历列表和修改元素。
未完待续---请关注---Java的集合框架---API文档深入研究2.0
到底啦!给靓仔一个关注吧!