集合进阶
迭代器
Iterable:可迭代的。
1. 为什么要有Iterable:每种集合,底层数据结构不同,取出方式不同,为了能以统一的一种方式取出所有集合的元素,定义迭代器。
2. 为什么Iterable是一个接口:接口的抽象方法,是一个标准,其实现类必须实现。保证所有的实现类实现了自己特有的迭代方法。
3. 为什么Iterable不做成一个抽象类:因为接口是多实现的,而抽象类是单继承的。
4. Iterable:它的所有的实现类都是可以被迭代输出的。
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
// Iterable的抽象方法返回Iterator
Iterator<String> it = list.iterator();// 迭代器
while(it.hasNext()){// one two three four five
System.out.println(it.next());
}
5. Iterator相当于一个光标,开始指向开始的地方,当迭代器迭代一次之后,光标指向最后一个值,不能二次迭代。
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
Iterator<String> it = list.iterator(); while(it.hasNext()){// one two three four five
String str = it.next();
System.out.print(it.next());
}
while(it.hasNext()){// 无输出
String str = it.next();
System.out.println("2:"+str);
}
6. ListIterator
ConcurrentModificationException:并发修改异常
在使用迭代器迭代的过程中,如果使用list增加、删除或修改元素,则会报并发修改异常。
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = it.next();
if(str.equals("one")){
// ConcurrentModificationException
list.add("list");
}
}
System.out.println(list);
Iterator的子接口:ListIterator,专门用于List集合,提供了add和remove方法解决迭代过程中并发修改异常。
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
ListIterator<String> it = list.listIterator();
while(it.hasNext()){
String str = it.next();
if(str.equals("one")){
it.add("list");
}
}
// [one, list, two, three, four, five]
System.out.println(list);
ListIterator还提供了逆序迭代:
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
// 逆序迭代输出
ListIterator<String> it = list.listIterator(list.size());
while(it.hasPrevious()){// five four three two one
String str = it.previous();
System.out.println(str);
}
迭代器的简化应用——foreach的使用
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
// one two three four five
for(String str :list){
System.out.println(str);
}
List&Set
1. List&Set
List:
- 元素存入顺序和取出顺序一致(有序)
- 元素可以重复
- 可以使用get(i)的方式将元素取出
- List中删除、查找、判断是否包含依据是equals()方法
Set:hash(哈希,散列)算法 底层HashMap
- 元素存入顺序和取出顺序不一致(无序),注意无序不是随机顺序
- 元素会自动去重,不可以重复
- 没有get方法用于取出单个元素
- HashSet中去重依据的是hashCode()方法和equals()方法
- TreeSet:底层是二叉树
2. ArrayList和LinkedList的区别?
ArrayList、Vector、LinkedList都是List集合。
- ArrayList和Vector底层是数组,而LinkedList底层是双向链表。最多使用的是ArrayList
- 数组:添加元素非常耗时,查找元素比较快。
- 链表:查找耗时,添加元素比较快。
- 底层结构的不同决定了使用场景的不同
3. HashSet
在HashSet添加元素的过程中,先比较元素的hashCode()方法,如果hashCode()不同,则认为是两个对象,则存储。
如果hashCode()相同,则比较equals()方法,如果equals()不同,则认为是两个对象,则存储。
如果hashCode()相同,equals()也相同,则认为是同一个对象,则不存储。
- Java官方规定,重写equals,必须重写hashCode
- 如果两个对象的equals相等,则他们的hashCode一定相等,反之不成立。
- hashCode equals toString :Object的三大重写
4. TreeSet
set的特点:
- 元素存入顺序和取出顺序不一致
- 会自动将元素按照字典顺序进行排序
- 排序依据的是compareTo方法
对象想要放入TreeSet中,需要具有可比较性。如何具有可比较性?
- 1、类实现Comparable接口,提供comparTo方法,方法中定义排序的规则。 这里的方法返回值int:如果等于0,则认为是同一个对象,如果大于0,则排后面,如果小于0,在排前面。
- 2、在TreeSet中提供一个Comparator比较器的实现类,重写compare方法。优先选择本方案,比较灵活,可以使用在多个比较的场景。
牛刀小试
public class Person implements Comparable<Person>{
private String name;
private int age;
......
@Override
public int compareTo(Person o) {// 重写comparTo方法定义比较规则
if(this.getAge() != o.getAge()){
return this.getAge()-o.getAge();// 年龄从小到大,主码
}else {
return this.getName().compareTo(o.getName());//名字的字典顺序
}
}
// 测试类中代码
Set<Person> set = new TreeSet<Person>();
Person p1 = new Person("zhangsan",20);
Person p2 = new Person("lisi",18);
Person p3 = new Person("wangwu",20);
Person p4 = new Person("zhaoliu",19);
Person p5 = new Person("tianqi",20);
Person p6 = new Person("zhangsan",20);
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
set.add(p5);
set.add(p6);
for (Person person : set) {
System.out.println(person);
}
//Person [name=lisi, age=18]
//Person [name=zhaoliu, age=19]
//Person [name=tianqi, age=20]
//Person [name=wangwu, age=20]
//Person [name=zhangsan, age=20]