Iterator 迭代器
-
Iterator 接口 :JDK提供的遍历集合所有元素的接口
- 迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
* `public E next()`:返回迭代的下一个元素。 * `public boolean hasNext()`:如果仍有元素可以迭代,则返回 true。 * public void remove() {//删除元素
注意:在使用.hasnext().next方法时需交替出现类要具有迭代器 需要实现iterable接口
-
自定义类迭代器类需要实现Iterator<E>接口
并发异常问题:ConcurrentModificationException
-
原因:集合本身修改会引起modount版本号改变,而迭代器本身的版本号副本并未改变,所以会抛出异常
-
fair -fast机制----》快速失败机制
-
fast-fail事件产生的条件:当多个线程对Collection进行操作时,若其中某一个线程通过iterator去遍历集合时,该集合的内容被其他线程所改变;则会抛出ConcurrentModificationException异常。
fast-fail解决办法:通过util.concurrent集合包下的相应类去处理,则不会产生fast-fail事件。 -
tertor和Listiterator的区别和相同点
-
itertor 对 collection 进行迭代的迭代器
- ListIterator有add()方法,可以向List中添加对象,而Iterator不能
- ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
- ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
- 都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改
- 迭代器的实现原理
当遍历集合时,首先通过调用t集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。
Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素:
在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。
单例集合 --Java.util
Colection :单例集合的根接口,用于存储一系列符合某种规则的元素,有两个重要的子接口
* `public boolean add(E e)`: 把给定的对象添加到当前集合中 。
* `public void clear()` :清空集合中所有的元素。
* `public boolean remove(E e)`: 把给定的对象在当前集合中删除。
* `public boolean contains(E e)`: 判断当前集合中是否包含给定的对象。
* `public boolean isEmpty()`: 判断当前集合是否为空。
* `public int size()`: 返回集合中元素的个数。
* `public Object[] toArray()`: 把集合中的元素,存储到数组中。
LIst : 特点是元素有序,元素可重复,可通过索引检索 有三个实现类
接口介绍:public interface Linke extends Colection
1> 有序集合(也称序列) ,可通过索引精确访问每个位置
2> LIst接口提供了特殊的迭代器 LIstIterator,允许元素插入和更换 ,提供了从指定位置开始迭代的方法
3> 允许元素重复,可通过元素的 .equals() 比较是否为重复元素
4>List集合取出元素的方式可以采用:迭代器、增强for。
常用方法:
- `public void add(int index, E element)`: 添加到该集合中的指定位置上。
- `public E get(int index)`:返回集合中指定位置的元素。
- `public E remove(int index)`: 移除列表中指定位置的元素。
- `public E set(int index, E element)`:用指定元素替换集合中指定位置的元素。
- Vector :
实现类介绍:public class Vectorextends AbstractListimplements List, RandomAccess, Cloneable, Serializable
1>Vector类实现了可扩展的对象数组。
2>快速失败
3>每个向量尝试通过维护capacity和capacityIncrement优化存储capacityIncrement 。 capacity总是至少与矢量大小一样大; 通常较大,因为当向量中添加组分时,向量的存储空间大小capacityIncrement 。
public static void main(String[] args) {
Vector <String >vr=new Vector<>() ;
vr.add("A") ;
vr.add("B") ;
vr.add("C") ;
vr.add("D") ;
vr.add("E") ;
vr.add("F") ;
// 返回此向量的组件的枚举。
Enumeration <String>it=vr.elements();
while (it.hasMoreElements() ){
String s=it .nextElement() ;
System.out.print(s+" ");
}
System.out.println();
// 返回此 List 的部分视图,元素范围为从 fromIndex(包括)到 toIndex(不包括)。
List <String>list =vr .subList(1,4);
System.out.println(list);
Iterator <String>itor=vr.iterator() ;
while (itor .hasNext() ){
String s=itor .next() ;
System.out.print(s+" ");
}
}
- LinkedList :
实现类介绍
1>双链表实现了List和Deque接口。 实现所有可选列表操作,并允许所有元素(包括null )。
2>*请注意,此实现不同步 * 类外部同步/包装 List list = Collections.synchronizedList(new ArrayList(…));
3>快速失败
* `public void addFirst(E e)`:将指定元素插入此列表的开头。
* `public void addLast(E e)`:将指定元素添加到此列表的结尾。
* `public E getFirst()`:返回此列表的第一个元素。
* `public E getLast()`:返回此列表的最后一个元素。
* `public E removeFirst()`:移除并返回此列表的第一个元素。
* `public E removeLast()`:移除并返回此列表的最后一个元素。
* `public E pop()`:从此列表所表示的堆栈处弹出一个元素。
* `public void push(E e)`:将元素推入此列表所表示的堆栈。
* `public boolean isEmpty()`:如果列表不包含元素,则返回true。
** - ArraryList :
实现类介绍:public class ArrayListextends AbstractListimplements List, RandomAccess, Cloneable, Serializable
1>可调整大小的数组的实现List接口。 实现所有可选列表操作,并允许所有元素,包括null
2>*请注意,此实现不同步 * 类外部同步/包装 List list = Collections.synchronizedList(new ArrayList(…));
3> The iterators returned by this class’s个 iterator和listIterator方法是快速失败的 :如果列表在任何时间从结构上修改创建迭代器之后,以任何方式除非通过迭代器自身remove种或add方法,迭代器都将抛出一个ConcurrentModificationException 。 因此,面对并发修改,迭代器将快速而干净地失败,而不是在未来未确定的时间冒着任意的非确定性行为。
请注意,迭代器的故障快速行为无法保证,因为一般来说,在不同步并发修改的情况下,无法做出任何硬性保证。 失败快速迭代器尽力投入ConcurrentModificationException 。 因此,编写依赖于此异常的程序的正确性将是错误的:迭代器的故障快速行为应仅用于检测错误。
ArrayList和LinkedList的区别和相同点:
相同点:1.继承关系:List接口下的实现类,具有List提供的方法
2.有序性:数据按照插入时有序
3.重复性:集合中的元素可以重复
4.null值:都可以存储Null值
5.安全性:都是非线程安全的集合
不同点:1.数据结构: LinkedList是双向链表 ArrayList是数组
2.特有方法:例如:addFirst addLast 实现了Deque;
3.效率:ArrayList查询效率高 Linked List添加删除效率高
ArrayList查询元素的效率趋近O(1) Linked List增加的元素趋近于O(1)
应用场景不同: Array List在查询较多的情况下优先考虑 LinkedList在添加、修改较多的情况下优先考虑
Set : 特点是元素无序,元素不可重复,没有索引 有两个实现类
接口介绍:public interface Set<E>extends Collection<E>
1> 不包含重复元素的集合。 更正式地,集合不包含一对元素e1和e2 ,使得e1.equals(e2) ,并且最多一个空元素。 正如其名称所暗示的那样,这个接口模拟了数学集抽象。
2>尝试对不符合条件的元素的操作,其完成不会导致不合格元素插入到集合中,可能会导致异常,或者可能会成功执行该选项。 此异常在此接口的规范中标记为“可选”。
3>Set集合取出元素的方式可以采用:迭代器、增强for。
** - HashSet :
实现类介绍:public class HashSetextends AbstractSetimplements Set, Cloneable, Serializable
1> 此类实现Set接口,由哈希表(实际为HashMap实例)支持。 对集合的迭代次序不作任何保证; 特别是,它不能保证订单在一段时间内保持不变。 这个类允许null元素。
哈希表:在JDK1.8
之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
eq:简单的来说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的
@Override
public boolean equals(Object o) {
Student personOne = (Student) obj;
return this.age==personOne.age&&this.equals(((PersonOne) obj).name);
}
@Override
public int hashCode() {
return name.hashCode+age*38;
}
- LinkedHashSet :
实现类介绍:public class LinkedHashSetextends HashSetimplements Set, Cloneable, Serializable
1> 哈希表和链表实现了Set接口,具有可预测的迭代次序。这种实现不同于HashSet,它维持于所有条目的运行双向链表。 该链表定义了迭代排序,它是将元素插入集合(插入顺序 ) 的顺序 。 请注意,如果一个元件被重新插入到组插入顺序不受影响 。
2>LinkedHashSet的迭代需要与集合的大小成比例的时间,无论其容量如何。 HashSet的迭代可能更昂贵,需要与其容量成比例的时间。
3>链接哈希集具有影响其性能的两个参数: 初始容量和负载因子 。 它们的定义精确到HashSet 。
4>请注意,此实现不同步类外部同步 Set s = Collections.synchronizedSet(new LinkedHashSet(…));
5>快速失败
public class LinkedHashSetDemo {
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<String>();
set.add("bbb");
set.add("aaa");
set.add("abc");
set.add("bbc");
Iterator<String> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
结果:
bbb
aaa
abc
bbc
** - TreeSet :
实现类介绍:public class TreeSetextends AbstractSetimplements NavigableSet, Cloneable, Serializable
1>此实现提供了基本的操作(保证的log(n)时间成本add , remove和contains )。
2>快速失败
3> 请注意,此实现不同步类外部同步SortedSet s = Collections.synchronizedSortedSet(new TreeSet(…));
Iterator iterator =ts .iterator();
while (iterator .hasNext() ){
Chilgren c=(Chilgren)iterator .next();
System.out.println(c.getName() +" "+c.getAge() );
}/*返回此 set 中大于等于给定元素的最小元素;如果不存在这样的元素,则返回 null。eeewwwd*/
Chilgren C= ts .ceiling(new Chilgren("四个",16) ) ;
System.out.println(C.getName() +" "+C .getAge() );
Collections
2.1 常用功能
java.utils.Collections
是集合工具类,用来对集合进行操作。部分方法如下:-
public static <T> boolean addAll(Collection<T> c, T... elements)
:往集合中添加一些元素。
public static void shuffle(List<?> list) 打乱顺序
:打乱集合顺序。public static <T> void sort(List<T> list)
:将集合中元素按照默认规则排序。public static <T> void sort(List<T> list,Comparator<? super T> )
:将集合中元素按照指定规则排序。
public class CollectionsDemo {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
//原来写法
//list.add(12);
//list.add(14);
//list.add(15);
//list.add(1000);
//采用工具类 完成 往集合中添加元素
Collections.addAll(list, 5, 222, 1,2);
System.out.println(list);
//排序方法
Collections.sort(list);
System.out.println(list);
}
}
结果:
[5, 222, 1, 2]
[1, 2, 5, 222]
Comparator比较器
我们还是先研究这个方法
public static <T> void sort(List<T> list)
:将集合中元素按照默认规则排序。
public class CollectionsDemo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("cba");
list.add("aba");
list.add("sba");
list.add("nba");
//排序方法
Collections.sort(list);
System.out.println(list);
}
}
我们使用的是默认的规则完成字符串的排序,那么默认规则是怎么定义出来的呢?
说到排序了,简单的说就是两个对象之间比较大小,那么在JAVA中提供了两种比较实现的方式,一种是比较死板的采用java.lang.Comparable
接口去实现,一种是灵活的当我需要做排序的时候在去选择的java.util.Comparator
接口完成。
那么我们采用的public static <T> void sort(List<T> list)
这个方法完成的排序,实际上要求了被排序的类型需要实现Comparable接口完成比较的功能,在String类型上如下:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
String类实现了这个接口,并完成了比较规则的定义,但是这样就把这种规则写死了,那比如我想要字符串按照第一个字符降序排列,那么这样就要修改String的源代码,这是不可能的了,那么这个时候我们可以使用
public static <T> void sort(List<T> list,Comparator<? super T> )
方法灵活的完成,这个里面就涉及到了Comparator这个接口,位于位于java.util包下,排序是comparator能实现的功能之一,该接口代表一个比较器,比较器具有可比性!顾名思义就是做排序的,通俗地讲需要比较两个对象谁排在前谁排在后,那么比较的方法就是:
public int compare(String o1, String o2)
:比较其两个参数的顺序。两个对象比较的结果有三种:大于,等于,小于。
如果要按照升序排序,
则o1 小于o2,返回(负数),相等返回0,01大于02返回(正数)
如果要按照降序排序
则o1 小于o2,返回(正数),相等返回0,01大于02返回(负数)
操作如下:
public class CollectionsDemo3 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("cba");
list.add("aba");
list.add("sba");
list.add("nba");
//排序方法 按照第一个单词的降序
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.charAt(0) - o1.charAt(0);
}
});
System.out.println(list);
}
}