Collection容器:无序、不唯一
List和Set是Collection的两个子接口。
List中包含:ArrayList、LinkedList、Vector
ArrayList、Vector的底层实现基本一致,底层都是Object数组。是一个对数组做了封装的容器类。该容器的优缺点和数组基本一致。比数组的优点在于,提供了对数组元素的封装的方法。
缺点:
1、 插入,删除元素效率低,需要移动大量的元素。
2、 根据内容查找元素效率低。
3、 根据索引查找元素效率高。
Vector 与 ArrayList 的区别
底层数据结构相同,都是 Object 类型的数组
(1) Vector 的 add()方法是同步方法,ArrayList 的 add() 方法是非同步方法
(2) Vector 扩容每次扩充 1 倍 ,ArrayList 每次扩充 0. 5 倍
(3) Vector是在调用构造方法时,直接初始化容量为10, ArrayList 是在第一次调用添加方法时,初始化容 量为 10
(4) Vector 的版本是 JDK1.0,ArrayList,JDK1.2 版
(5) Vector 是线程同步的,安全性高,效率低, ArrayList 是线程非同步的,安全性低,效率高
**LinkedList:**底层使用双向链表实现。在该类中包含了头结点和尾部节点的引用。First和last可以实现双向的遍历。
优点:
1、插入和删除元素效率高,前提是先找到插入和删除的位置,这个查找的过程效率低。
2、根据内容查找元素,根据索引查找元素效率低。遍历元素效率低。
问:如何选用ArrayList、LinkedList、Vector?
- 需要线程安全时,用Vector。
- 不存在线程安全问题时,并且查找较多用ArrayList(一般使用它)。
- 不存在线程安全问题时,增加或删除元素较多用LinkedList。
HashSet
a) 特点:元素无序,唯一、底层使用哈希表实现。
i. 元素的无序性:元素的位置是通过计算元素对象的哈希码来确定的。通过调用对象的hashCode()方法来获得。
ii. 唯一性:hashCode() + equals 同时保证的。 要求相同(内容)的对象具有相同的哈希码,才能保证2个相同的对象存放在相同的位置,才能进行 equals 比较的判断。但是Object 默认的hashCode()的实现,不同的对象的哈希码是不一样的(即使内容相同)。
iii. 为了保证元素的无序和唯一,必须将HashSet 中的元素的类型中要重写hashCode 和 equals 方法。
iv. 重写hashCode 方法要依赖的规则:如果两个对象的内容相同,那么哈希码必须一致! 如果两个对象的哈希码一致,那么内容是否一致呢??不一定!如果两个对象的哈希码一致,那么equals 比较是否一致?不一定!如果两个对象equals 比较一致,那么哈希码是否必须一致?是的,必须一致!
TreeSet:
b) 特点:元素有序(升序),唯一的。底层使用红黑树(一种二叉树)。
i. 有序是通过什么保证的?
比较器(内部比较器:java.lang.Comparable 外部比较器:java.util.Comparator)
4. 要么让元素具有内部比较的功能,实现内部比较器接口。
5. 要么指定TreeSet 的外部比较器。
元素的唯一性如何保证的?也是通过比较器。比较的结果为0,那么就不在添加了。
容器的遍历方式:
ArrayList、Vector、LinkedList可以用: 普通 for 循环 、 for-each 、 迭代器。
LinkedList不建议使用普通for循环,遍历效率非常慢。
for-each 、 迭代器两种再容器中是比较通用的两种遍历方法。
Map集合:(键值对)
1. HashMap
c) HashMap 中的元素是一对数据(key,value)。底层使用哈希表来实现。通过计算key的哈希码来决定key 所在的元素的位置。所以Key 的类型需要重写hashCode 和 equals 方法。Key 的特点:无序,唯一,可以有一个null。Value 的特点:无序,不唯一,可以有多个null.
d) HashMap中元素中的key 的特点和 HashSet 中元素的特点一致。
e) 哈希表的扩容问题:loadFactor 填充因子,默认值为0.75.当一维数组被占用的元素达到了该因子的百分比%75,那么就进行扩容。
f) HashSet 底层使用 HashMap 实现。只使用了HashMap 的key 部分。
2. TreeMap
a) 元素是一对数据,key和value ,key 是升序,惟一的,value 是无序,不唯一的。
b) 底层二叉树。
c) TreeSet 使用 TreeMap实现。
3. Hashtable
a) 特点:底层使用哈希表,元素是键值对对象。是早期的一个映射容器类,线程安全的,效率相对较低,继承了Dictionary 类,Map 接口出现之后,又实现了该接口。Key 是无序唯一的,value 无序不唯一的,key 和 value 都不能是null.
着重讲一下:TreeSet和TreeMap在存储自定义对象的时候,要求必须具备比较规则(保证有序和唯一)
有两种方法:外部比较器(实现java.util.Comparator接口)、内部比较器(实现java.lang.Comparable,重写CompareTo方法)
具体代码如下:
1、使用内部比较器:
public class TextTreeSet {
public static void main(String[] args) {
Set<Student> tt=new TreeSet<Student>();//实例化TreeSet对象,传入自定义对象Student
Student ss=new Student(2,"xiali");
Student s2=new Student(1,"dali");
tt.add(ss);//将对象添加进去
tt.add(s2);
for (Student sss : tt) {//使用for-each实现遍历。Student中已经重写了ToString()方法
System.out.println(sss);
}
}
}
//实现implements Comparable<Student>接口,重写compareTo方法来实现内部比较器
class Student implements Comparable<Student>{
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(int id, String name) {//带参构造
super();
this.id = id;
this.name = name;
}
@Override
public int compareTo(Student o) {
if (this.id > o.id) {
return 1;
} else if (this.id < o.id) {
return -1;
} else {
return 0;
}
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
}
2、使用外部比较器代码如下:
public class TextTreeSet {
public static void main(String[] args) {
Comparator<Student> my=new MyComparator();//实例化自定义的比较器
Set<Student> tt=new TreeSet<Student>(my);//将比较器放入TreeSet中,直接使用即可。
Student ss=new Student(2,"xiali");
Student s2=new Student(1,"dali");
tt.add(ss);
tt.add(s2);
for (Student sss : tt) {
System.out.println(sss);
}
}
}
class Student{
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(int id, String name) {//带参构造
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
}
//实现外部比较器,实现java.util.Comparator接口,重写compare方法
class MyComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getId()-o2.getId();//返回按id排序
}
}
着重:HashSet、HashMap、HashTable在存储自定义对象时为了保证无序和唯一,要求重写hashcode()和equals()方法
如:上述例子中的Student对象:
class Student{
private int id;
private String name;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
快速生成hashcode()和equals()方法的快捷键为:shift+alt+s。祥见下图步骤: