集合
知识框架:
集合概述
集合实际上就是一个容器,可以用来容纳其他类型的数据。
集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,集合当中存储的都是java对象的内存地址。
在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中存储元素,相当于将数据放到了不同的数据结构当中。
Java 集合主要有 3 种重要的类型:
List:是一个有序集合,可以放重复的数据。
Set:是一个无序集合,不允许放重复的数据。
Map:是一个无序集合,集合中包含一个键对象,一个值对象,键对象不允许重复,值对象可以重复(身份证号—姓名)。
Collection 和 Iterator
Collection 是 List 和 Set 的父接口,在 Collection 中定义了一些主要方法。
其中:contains()方法中调用了equals()方法。
remove()方法中调用了equals()方法
所以存放在集合中的类型一定要重写equals()方法。
关于 Iterator 接口说明,Iterator 称为迭代接口,通过此接口可以遍历集合中的数据,此接口主要方法为:
List接口
List接口概述
List 接口下面主要有两个实现 ArrayList 和 LinkedList,他们都是有顺序的,也就是放进去是什么顺序,取出来还是什么顺序,也是基于线性存储,可以看作是一个可变数组。
ArrayList:查询数据比较快,添加和删除数据比较慢(基于可变数组) 。
LinkedList:查询数据比较慢,添加和删除数据比较快(基于链表数据结构)。
Vector:Vector 已经不建议使用,Vector 中的方法都是同步的,效率慢,已经被 ArrayList取代。
Stack 是继承 Vector 实现了一个栈,栈结构是后进先出,目前已经被 LinkedList 取代。
Set 接口
哈希表
哈希表是一种数据结构,哈希表能够提供快速存取操作。哈希表是基于数组的,所以也存在缺点,数组一旦创建将不能扩展。
正常的数组,如果需要查询某个值,需要对数组进行遍历,只是一种线性查找,查找的速度比较慢。如果数组中的元素值和下标能够存在明确的对应关系,那么通过数组元素的值就可以换算出数据元素的下标,通过下标就可以快数定位数组元素,这样的数组就是哈希表。
例如以下哈希表:
元素下标=元素值-10,此时的示例 hashcode 就是和数组下标一致了,取得 hashcode 方法如下:
//取得 hashCode
pubic int hashCode(int value) {
return value – 10;
}
HashSet
HashSet 中的数据是无序的不可重复的。HashSet 按照哈希算法存取数据的,具有非常好性能,它的工作原理是这样的,当向 HashSet 中插入数据的时候,他会调用对象的 hashCode 得到该对象的哈希码,然后根据哈希码计算出该对象插入到集合中的位置。
import java.util.*;
public class HashSetTest01 {
public static void main(String[] args) {
//它是无序的,不重复
Set set = new HashSet();
set.add("a");
set.add("b");
set.add("c");
//输出是无序的
for (Iterator iter=set.iterator();
iter.hasNext();) {
System.out.println(iter.next());
}
//加入重复数据
set.add("a");
System.out.println("");
for (Iterator iter=set.iterator();
iter.hasNext();) {
System.out.println(iter.next());
}
String s1 = "abc";
String s2 = "abc";
System.out.println("s1 equals s2 ," + s1.equals(s2));
//equals 相等,hashcode 一定是相等的
System.out.println("s1.hashCode=" + s1.hashCode());
System.out.println("s2.hashCode=" + s2.hashCode());
String s3 = "ddddd";
System.out.println("s1 equlas s3," + s1.equals(s3));
System.out.println("s3.hashCode=" + s3.hashCode());
}
}
equals 和 hashCode
在我们自己写的程序中如果覆盖了equals 和hashCode,当 hashCode 相同,它会调用equals 进行比较,如果equals 比较相等将不加把此元素加入到Set 中,但 equals 比较不相等会重新根据hashCode 换算位置仍然会将该元素加入进去的。
需要注意的是在向 HashSet 或HashMap 中加入数据时必须同时覆盖equals 和 hashCode 方法,应该养成一种习惯覆盖equals 的同时最好同时覆盖hashCode。
Java 要求:
两个对象equals 相等,那么它的hashcode 相等。
两个对象equals 不相等,那么它的hashcode 并不要求它不相等,但一般建议不相等。
hashcode 相等不代表两个对象相等(采用equals 比较)。
TreeSet
import java.util.*;
public class TreeSetTest01 {
public static void main(String[] args) {
Set set = new TreeSet();
set.add(9);
set.add(2);
set.add(5);
set.add(1);
//不能放入重复数据
set.add(5);
for (Iterator iter=set.iterator();
iter.hasNext();) {
Integer v = (Integer)iter.next();
System.out.println(v);
}
}
}
Map接口
Map中可以放置键值对,也就是每一个元素都包含键对象和值对象,Map 实现较常用的为HashMap,HashMap对键对象的存取和HashSet 一样,仍然采用的是哈希算法,所以如果使用自定类作为Map 的键对象,必须复写equals 和hashCode 方法。
Comparable 和 Comparator 的区别?
一个类实现了 Camparable 接口则表明这个类的对象之间是可以相互比较的,这个类对象组成的集合就可以直接使用sort 方法排序。
Comparator 可以看成一种算法的实现,将算法和数据分离,Comparator 也可以在下面两种环境下使用:
1、类的没有考虑到比较问题而没有实现 Comparable,可以通过 Comparator 来实现排序而不必改变对象本身。
2、可以使用多种排序标准,比如升序、降序等。