一. 集合概述
Java集合是使程序能够存储和操纵元素不固定的一组数据。所有Java集合类都位于java.util中。集合中存放基本数据类型时,需要存放对应的基本类型包装类。
二. 层次结构
Java的集合类主要由两个接口派生而出:Collection和Map。Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。
下面我们列举出最常用的几个子接口和实现类:
Collection ——> List ——> ArrayList类
Collection ——> List ——> LinkedList类
Collection ——> Set ——> HashSet类
Collection ——> Set ——> SortedSet接口 ——> TreeSet类
Map ——> HashMap类
Map ——> SortedMap ——> TreeMap类
三.Collection介绍
Collection接口是List接口和Set接口的父接口,它定义的方法可以用于操作List集合和Set集合。
Collection接口定义的方法
方法 描述
boolean add(Object o) 该方法用于向集合里添加一个元素,添加成功返回true
void clear() 清除集合里的所有元素,将集合长度变为0
boolean contains(Object o) 返回集合里是否包含指定元素
boolean containsAll(Collection c) 返回集合里是否包含集合c里的所有元素
int hashCode() 返回此collection的哈希码值
boolean isEmpty() 返回集合是否为空,当集合长度为0时,返回true
Iterator iterator() 返回一个Iterator对象,用于遍历集合里的元素
boolean remove(Object o) 删除集合中指定元素o,当集合中包含了一个或多个元素o时,这些元素将被删除,该方法将返回true
boolean removeAll(Collection c) 从集合中删除集合c里包含的所有元素,如果删除了一个或一个以上的元素,返回true
boolean retainAll(Collection c) 从集合中删除不在集合c里包含的元素,如果删除了一个或一个以上的元素,返回true
int size() 返回集合中的元素个数
Object[] toArray() 该方法把集合转换成一个数组,所有集合元素变成对应的数组元素
四. Iterator
【介绍】
- Collection接口的iterator()和toArray()方法都用于获得集合中的所有元素,前者返回一个Iterator对象,后者返回一个包含集合中所有元素的数组。
- Iterator接口隐藏底层集合中的数据结构,提供遍历各种类型集合的统一接口。
【接口主要方法】
方法 描述
Boolean hasNext() 如果被迭代的集合有下一个元素,则返回true
Object next() 返回集合里下一个元素
void remove() 删除集合里上一次next方法返回的元素
【for与iterator对比】
Iterator的好处在于可以使用相同方式去遍历集合中元素,而不用考虑集合类的内部实现。
使用Iterator来遍历集合中元素,如果不再使用List转而使用Set来组织数据,则遍历元素的代码不用做任何修改
使用for来遍历,那所有遍历此集合的算法都得做相应调整,因为List有序,Set无序,结构不同,他们的访问算法也不一样
for循环需要下标
五. List
【特点】
List是一个有序集合,既存入集合的顺序和取出的顺序一致
List集合允许添加的元素重复
List不单单继承了Collection的方法,还增加了一些新的方法。
方法 描述
void add(int index, Object element) 将元素element插入到List的index处
boolean addAll(int index, Collection c) 将集合c所包含的所有元素都插入在List集合的index处
Object get(int index) 返回集合index处的元素
int indexOf(Object o) 返回对象o在List集合中出现的位置索引
int lastIndexOf(Object o) 返回对象o在List集合中最后一次出现的位置索引
Object remove(int index) 删除并返回index索引处的元素
Object set(int index, Object element) 将index索引处的元素替换成element对象,返回新元素
List subList(int fromIndex, int toIndex) 返回从索引fromIndex(包含)到索引toIndex(不包含)处所有集合元素组成的子集合
5.1 ArrayList、Vector
【特点对比】
- ArrayList和Vector都是基于数组实现的,两者用法差不多
- ArrayList随机查询效率高,随机增删元素效率较低
- Vector提供了一个Stack子类,模拟“栈”数据结构——”先进后出”
- ArrayList是线程不安全的,Vector是线程安全的
【重点示例】
ArrayList中存放对象,在判断包含或者删除元素时,通过equals比较是否为同一个对象,然后进行操作
5.2 LinkedList
【特点】
- LinkedList是双向链表实现的
- 随机查询效率低,随机增删效率高
【LinkedList新增方法】
方法 描述
void addFirst(Object e) 将指定元素插入该集合的开头
void addLast(Object e) 将指定元素插入该集合结尾
boolean offerFirst(Object e) 将指定元素插入该集合的开头,成功返回true
boolean offerLast(Object e) 将指定元素插入该集合结尾
boolean offer(Object e) 将指定元素插入该集合结尾
Object getFirst() 获取,但不删除集合第第一个元素
Object getLast() 获取,但不删除集合最后一个元素
Object peekFirst() 获取,但不删除该集合第一个元素,如果集合为空,则返回null
Object peekLast() 获取,但不删除该集合最后一个元素,如果集合为空,则返回null
Object pollFirst() 获取,并删除该集合第一个元素,如果集合为空,则返回null
Object pollLast() 获取,并删除该集合最后一个元素,如果集合为空,则返回null
Object removeFirst() 获取,并删除该集合的第一个元素
Object removeLast() 获取,并删除该集合的最后一个元素
Object pop() pop出该集合的第一个元素(类似删除)
void push(Object e) 将一个元素push到集合(添加到第一位)
【总结】
List主要有两个实现ArrayList和LinkedList,他们都是有顺序的,也就是放进去是什么顺序,取出来还是什么顺序
ArrayList——遍历、查询数据比较快,添加和删除数据比较慢(基于可变数组)
LinkedList——查询数据比较慢,添加和删除数据比较快(基于链表数据结构)
Vector——Vector已经不建议使用,Vector中的方法都是同步的,效率慢,已经被ArrayList取代
Stack——继承Vector实现的栈,栈结构是先进后出,但已被LinkedList取代
六. Set
【特点】
- Set是一个无序集合,既存入集合的顺序和取出的顺序不一致
- Set集合中元素不重复
【常用方法】
方法 描述
boolean add(E e) 如果此set中尚未包含指定元素,则添加指定元素
boolean isEmpty() 如果此set不包含任何元素,则返回true
boolean contains(Object o) 如果此set包含指定元素,则返回 true
boolean remove(Object o) 如果指定元素存在于此set中,则将其移除
int size() 返回此set中的元素的数量
void clear() 从此set中移除所有元素
七. Map接口
Map用于保存具有映射关系的数据,因此Map集合里保存两组值。
- 一组值用于保存key,一组值用于保存value
- key~value之间存在单向一对一关系,通过指定key可以找到唯一一个value值
- key和value都可以是任何引用类型对象
- 允许存在value为null,但是只允许存在一个key为null
【常用方法】
方法 描述
V put(K key, V value) 将指定的值与此映射中的指定键关联
boolean containsKey(Object key) 如果此映射包含指定键的映射关系,则返回true
boolean containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回true
boolean isEmpty() 如果此映射未包含键-值映射关系,则返回true
V get(Object key) 返回指定键所映射的值,如果此映射不包含该键的映射关系,则返回null
Set keySet() 返回此映射中包含的键的set集合
Collection values() 返回此映射中包含的值的Collection集合
Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射关系的set集合
boolean equals(Object o) 返回指定的对象与此映射是否相等
int hashCode() 返回此映射的哈希码值
V remove(Object key) 如果存在一个键的映射关系,则将其从此映射中移除
void clear() 从此映射中移除映射关系
int size() 返回此映射中的键-值关系数
7.1HashMap类
【特点】
key无序不可重复
底层是哈希表
【哈希表实现原理】
HashMap实际上是一个"链表的数组"的数据结构,每个元素存放链表头结点的数组,即数组和链表的结合体。
当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。
只有相同的hash值的两个值才会被放到数组中的同一个位置上形成链表。
如果这两个Entry的key通过equals比较返回true,新添加Entry的value将覆盖集合中原有Entry的value,但key不会覆盖。
【总结】
HashMap中key的hashCode值决定了<k,v>键值对组成的entry在哈希表中的存放位置。
HashMap中key通过equals()比较,确定是覆盖key对应的value值还是在链表中添加新的entry。
综合前两条,需要重写hashCode()和equals()方法。
7.2HashSet回顾
特点
- HashSet底层由HashMap实现
- 无序不可重复
八. 泛型
泛型是指所操作的数据类型被指定为一个参数,在用到的时候再指定具体的类型。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。
【示例】 - 定义一个对象池对象,可以根据需求存放各种类型对象。
class ProjectPool{
private List list = new ArrayList();
public void add(T t){
list.add(t);
}
public int size(){
return list.size();
}
} - 集合中使用泛型
List stuList = new ArrayList();
【总结】
- 泛型能更早的发现错误,如类型转换错误
- 使用泛型,那么在编译期将会发现很多之前要在运行期发现的问题
- 代码量往往会少一些、运维成本减少
- 抽象层次上更加面向对象
九.Comparable和Comparator比较
Comparable为可排序的,实现该接口的类的对象自动拥有可排序功能。(自比较)
Comparator为比较器,实现该接口可以定义一个针对某个类的排序方式。(外部比较)
Comparator与Comparable同时存在的情况下,前者优先级高。
Comparator更好,使用更加灵活。
示例:
public class User implements Serializable, Comparable {
private static final long serialVersionUID = 1L;
private int age;
private String name;
public User (){}
public User (int age, String name){
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(User o) {
return this.age - o.age;
}
@Override
public String toString() {
return “[user={age=” + age + “,name=” + name + “}]”;
}
}
在定义一个Comparator实现类MyComparator
public class MyComparator implements Comparator {
@Override
public int compare(User o1, User o2) {
return o1.getName().charAt(0)-o2.getName().charAt(0);
}
}
最后是测试类:Main
public class Main {
public static void main(String[] args) {
User u1 = new User(12, “xiaohua”);
User u2 = new User(10, “abc”);
User u3 = new User(15,“ccc”);
User[] users = {u1,u2,u3};
System.out.print(“数组排序前:”);
printArray(users);
System.out.println();
Arrays.sort(users);
System.out.print(“数组排序1后:”);
printArray(users);
System.out.println();
Arrays.sort(users, new MyComparator());
System.out.print(“数组排序2后:”);
printArray(users);
System.out.println();
Arrays.sort(users, Comparator.reverseOrder());// 针对内置的排序进行倒置
System.out.print(“数组排序3后:”);
printArray(users);
}
public static void printArray (User[] users) {
for (User user:users) {
System.out.print(user.toString());
}
}
}