集合框架
集合框架的由来:对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定,就是使用集合容器进行存储
集合的特点
- 1、用于存储对象的容器
- 2、集合的长度是可变的
- 3、集合中不可以存储基本的数据类型
集合的数据结构
集合容器因为内部的数据结构不同,有多种具体的容器,不断向上抽取,就形成了集合框架
集合框架的顶层的Collection接口:
集合框架常用的方法
- 1、添加
- boolean add(Object obj);//一次添加一个
- boolean addAll(Collection coll);//一次添加一个集合
- 2、删除
- boolean remove(Object obj);//一次删除一个
- boolean removeAll(Collection coll);//一次删除一个集合
- void clear();//删除集合中的所有元素
- 3、判断
- boolean contains(Object obj);//是否含有某个元素
- boolean containsAll(Collection coll);//是否含有某个集合
- boolean isEmpty():判断集合中是否含有元素
- 4、获取
- int size():
- Iterator iterator():取出元素的方式:迭代器。该对象必须依赖于具体容器,因为每一个容器的数据结构都不同。所以该迭代器对象是在容器中进行内部实现的。对于使用容器者而言,具体的实现不重要,只要通过容器获取到该实现的的迭代器的对象即可,也即是iterator方法。
- 5、其他:
- boolean retainAll(Collection coll):取交集,如 c1.retainsAll(c2);c1中保留和c2中相同的元素,删除不同的元素
- Object[] toArray():将集合转成数组
集合Collection下的子接口
- List 有序(存入和取出的顺序一致),元素都有索引(角标),元素可以重复
- Set 元素不允许重复,无序。
List特有的常见方法
都可以操作角标
- 添加
- void add(index,element)
- void add(index,Collection);
- 删除
- Object remove(index);
- 修改
- Object set(index,element);
- 获取
- Object get(index);
- int indexOf(Object);
- int lastIndexOf(Object);
- List subList(from , to );获取list的子集合,包含from位置的元素,不含to位置的元素
- 注意:
/*以下代码通过Iterator遍历List集合,在迭代过程中,向list集合增加元素,会报出java.util.ConcurrentModificationException异常。即在Iterator迭代过程中不允许修改集合
*/
Iterator it = list.iterator();
while(it.hasNext()){
Object obj = it.next(); //java.util.ConcurrentModificationException
if(obj.equals("abc2")){
list.add("abc9");
}
else
System.out.println("next:"+obj);
}
//此时可以通过ListIterator进行迭代,迭代过程中通过ListIterator对象操作集合
ListIterator it = list.listIterator();
//它可以实现在迭代过程中完成对元素的增删改查。注意:只有list集合具备该迭代功能
while(it.hasNext()){
Object obj = it.next();
if(obj.equals("abc2")){
it.add("abc9");
}else
System.out.println("next:"+obj);
}
List接口的具体实现
- Vector:内部是数组数据结构,是同步的。
- ArrayList:内部是数组数据结构,是不同步的。代替Vector,查询速度快。
- ArrayList容器中判断对象是否相同依据对象的equals方法。
- 如调用ArrayList的 boolean contains(Object obj)\ boolean remove(Object obj)等方法时,依据obj中的equals方法如何实现判断对象是否相同
- LinkedList:内部是链表数据结构,非同步的。增删元素的速度很快。
- jdk1.6版本之前,如果LinkedList为空,调用getFirst()\getLast()\removeFirst\removeLast()方法会报异常(NoSuchElementException),jdk1.6新增peekFirst()\peekLast()\pollFirst\pollLast(),如果此时LinkedList为空,则直接返回null,不会抛异常。
set集合详解
set元素不可以重复,是无序的,Set接口中的方法和Collection是一致的。
- HashSet:
- 内部数据结构是哈希表,是不同步的
- 哈希表确定元素是否相同
- 1、判断的是两个元素的哈希值是否相同,如果相同,再判断两个对象的内容是否相同。
- 2、判断哈希值是否相同,其实判断的是对象的hashCode方法。判断内容是否相同,用的是equals方法。
- 注意:如果哈希值不同,是不需要判断equals的。
- 使用元素的hashCode方法来确定位置,如果位置相同,再通过元素的equals来确定是否相同
//案例:将Person对象存入HashSet中,当姓名和年龄相同时,认为是同一对象。重写hashCode方法与equals方法
public class Person {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public int hashCode() {
System.out.println(this+"......hasCode");
return this.name.hashCode()+age * 39;
}
public boolean equals(Object obj) {
if(this == obj){
return true;
}
if(! (obj instanceof Person)){
throw new ClassCastException("类型错误");
}
Person p = (Person)obj;
System.out.println(this+"....equals....."+p);
return this.name.equals(p.name) && this.age == p.age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
- LinkedHashSet:有确定的迭代顺序的Set接口的实现
- TreeSet:可以对set集合中的元素进行排序,是不同步的
- 判断元素唯一性的方式:就是根据比较方法(compareTo)的返回结果是否是0,是0,就是相同的元素,不存。
- TreeSet对元素进行排序的方式:
- 让元素自身具备比较功能,元素需要实现Compareble接口,覆盖compareTo方法,如:
//Person类继承Comparable接口,实现compareTo方法
public class Person implements Comparable{
......
public int compareTo(Object obj) {
if( !(obj instanceof Person)){
return 0;
}
Person p = (Person)obj;
int temp = this.age - p.age;
return temp == 0 ? this.name.compareTo(p.name) : temp;
}
}
-
-
- 让集合自身具备比较功能,定义一个自定义的比较类实现Comparator接口,覆盖compare方法。将该类对象作为参数传递给TreeSet集合的构造函数。如:
-
//自定义实现Comparator接口的比较类
public class ComparatorByName implements Comparator {
public int compare(Object obj1, Object obj2) {
if(!(obj1 instanceof Person)||!(obj2 instanceof Person )){
return 0;
}
Person p1 = (Person)obj1;
Person p2 = (Person)obj2;
int temp = p1.getName().compareTo(p2.getName());
return temp == 0 ? p1.getAge() - p2.getAge() : temp;
}
}
//创建TreeSet实例时,传入自定义的比较器
TreeSet set = new TreeSet(new ComparatorByName());
- 案例:TreeSet如何实现元素的按存入的顺序遍历
- TreeSet底层为二叉树,要求存入的元素必须有序。每存入一个元素都与根节点的元素比较,若大于根节点,则放根节点的右子树;若小于则放根节点的左子树;若相等,则不存入。通过迭代器遍历时,为二叉树的中序遍历,即值最小的先遍历出。
- 若按照对象存入的先后顺序遍历,则排序规则为后存入TreeSet集合中元素总是大于先存入的元素。则此时比较器应为:
//自定义实现Comparator接口的比较类
public class ComparatorByName implements Comparator {
public int compare(Object obj1, Object obj2) {
return 1;
}
//创建TreeSet实例时,传入自定义的比较器
TreeSet set = new TreeSet(new ComparatorByName());