一、迭代器
1.Iterator
概念:Iterator是一个接口,它是集合的迭代器,集合可以通过Iterator去遍历集合中的元素,常用API接口:
- hasNext():如果迭代器中还有元素,则返回true。
- next():返回迭代器中的下一个元素。
- remove():删除迭代器新返回的元素。
案例:使用Iterator遍历元素
public class Test {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");list.remove("bbb");Iterator<String> it = list.iterator();while(it.hasNext()){String element = it.next();System.out.println(element);}} }
案例:使用Iterator遍历元素,遍历到"bbb"时删除该元素
import java.util.ArrayList; import java.util.Iterator; public class Test {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");//modCount - 5(外部操作数(记录集合添加、删除的次数))//expectedModCount - 5(内部操作数)Iterator<String> it = list.iterator();while(it.hasNext()){it.remove();String element = it.next();if(element.equals("bbb")){//list.remove(element);//modCount - 6(这种方式会报错,原因是在遍历时,外部数与内部数不同,会产生脏数据)it.remove();//(Itr依赖于ArrayList对象的remove()去删除元素,重新将外部操作数赋值给内部操作数,保证内外部操作数一致不会出现脏数据)}}for (String element : list) {System.out.println(element);}} }
ps:详细见理解Iterator底层源码
2.ListIterator
概念:ListIterator的功能更加强大, 它继承于Iterator接口,只能用于各种List类型的访问。可以通过调用listIterator()方法产生一个指向List开始处的ListIterator, 还可以调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。
案例:使用ListIterator遍历元素
import java.util.ArrayList; import java.util.ListIterator;public class Test {public static void main(String[] args) { ArrayList<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");ListIterator<String> listIterator = list.listIterator();while(listIterator.hasNext()){String element = listIterator.next();System.out.println(element);}} }
案例:使用ListIterator遍历元素,遍历到"bbb"时删除
public class Test05 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");ListIterator<String> listIterator = list.listIterator();while(listIterator.hasNext()){String element = listIterator.next();if(element.equals("bbb")){listIterator.remove();}}for (String element : list) {System.out.println(element);}} }
案例:使用ListIterator遍历元素,遍历到"bbb"时添加"xyz"
import java.util.ArrayList; import java.util.ListIterator;public class Test {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");ListIterator<String> listIterator = list.listIterator();while(listIterator.hasNext()){String element = listIterator.next();if(element.equals("bbb")){listIterator.add("xyz");}}for (String element : list) {System.out.println(element);}} }
案例:使用ListIterator遍历元素,遍历到"bbb"时替换成"xyz"
import java.util.ArrayList; import java.util.ListIterator;public class Test {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");ListIterator<String> listIterator = list.listIterator();while(listIterator.hasNext()){String element = listIterator.next();if(element.equals("bbb")){listIterator.set("xyz");}}for (String element : list) {System.out.println(element);}} }
案例:使用ListIterator指定下标遍历元素
public class Test {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");ListIterator<String> listIterator = list.listIterator(1);while(listIterator.hasNext()){String element = listIterator.next();System.out.println(element);}} }
案例:使用ListIterator倒序遍历元素
import java.util.ArrayList; import java.util.ListIterator;public class Test {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");ListIterator<String> listIterator = list.listIterator(list.size());while(listIterator.hasPrevious()){String element = listIterator.previous();System.out.println(element);}} }
二、泛型
1.使用泛型的原因
JDK1.4以前:
- 装入集合的数据都会被当作Object对象来存放,从而失去了自己的实际类型。
- 从集合中取出元素时,需要进行强制类型转换。效率低,容易产生错误。
从JDK1.5开始,sun公司推出了泛型来解决上述问题:
在定义一个集合时就指定集合存储的对象的数据类型
如:Collection coll = new ArrayList();
存入数据时只能存入泛型指定的数据类型,如果存入其他数据类型,则会编译错误,避数据存入时的问题。coll.add(new Integer(1)); //编译错误
从集合中取出元素时,无需转型了。
如:String str1 = it.next();
优点
简化集合的使用
增强代码的可读性和稳定性
2.泛型限定
案例及解析:
import java.util.ArrayList;public class Test {//继承关系:Object.A.Bpublic static void main(String[] args) { }//?表示任意类型public static ArrayList<?> method01(){ ArrayList<Object> list = new ArrayList<>();ArrayList<A> list = new ArrayList<>();ArrayList<B> list = new ArrayList<>();return list; }//? extends A 表示A类型或者是A的子类类型public static ArrayList<? extends A> method02(){ArrayList<A> list = new ArrayList<>();ArrayList<B> list = new ArrayList<>();return list; }//? super A 表示A类型或者是A的父类类型public static ArrayList<? super A> method03(){ArrayList<A> list = new ArrayList<>();ArrayList<Object> list = new ArrayList<>();return list; } } public class A{} public class B extends A{}
3.泛型的使用
接口中使用泛型
public interface IManagerSystem<T> {public void add(T t);public void delete(T t);public ArrayList<T> query(); }
类中使用泛型
public class MyArrayList<E>{public void add(E e){}public void remove(E e){} }
三、集合(续)
1.LinkedList
使用
import java.util.LinkedList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ListIterator;public class Test{public static void main(String[] args) {LinkedList<String> list = new LinkedList<>();//添加数据list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");//设置指定下标上的元素list.set(1, "fff");//获取指定下标上的元素String str = list.get(1);System.out.println("获取指定下标上的元素:" + str);//fff//获取元素个数int size = list.size();System.out.println("获取元素个数:" + size);//5//在指定下标上添加元素list.add(2, "ggg");LinkedList<String> newList1 = new LinkedList<>();Collections.addAll(newList1, "aaa","bbb","ccc","ccc");//利用集合工具类(Collections)批量添加元素list.addAll(newList1);//将newList1中所有的元素都添加到list集合里末尾的位置LinkedList<String> newList2 = new LinkedList<>();Collections.addAll(newList2, "xxx","xxx","yyy","yyy","zzz","zzz");//利用集合工具类(Collections)批量添加元素list.addAll(3, newList2);//将newList2中所有的元素都添加到list集合里指定下标的位置//清空集合里所有的元素//list.clear();System.out.println("判断集合中是否包含指定元素:" + list.contains("aaa"));//trueSystem.out.println("判断集合中是否包含指定集合:" + list.containsAll(newList1));//trueSystem.out.println("获取元素在集合中第一次出现的下标:" + list.indexOf("ccc"));//12System.out.println("获取元素在集合中最后一次出现的下标:" + list.lastIndexOf("ccc"));//13//没有-true,有-falseSystem.out.println("判断集合里是否没有元素:" + list.isEmpty());//falselist.remove(9);//通过下标删除元素list.remove("水菜丽");//通过数据删除元素list.removeAll(newList1);//将list中有newList1的元素全部删除(去除交集)list.retainAll(newList2);//将list中有newList2的元素全部保留(保留交集)List<String> subList = list.subList(1, 4);//从开始下标处(包含)截取到结束下标处(排他)的元素,返回新的集合//将集合转换为数组Object[] array1 = subList.toArray();System.out.println(Arrays.toString(array1));//[xxx, yyy, yyy]//将集合转换为指定类型的数组String[] array2 = new String[3];subList.toArray(array2);System.out.println(Arrays.toString(array2));//[xxx, yyy, yyy]System.out.println("-----------------------------------------");//遍历集合 -- for循环for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}System.out.println("-----------------------------------------");//遍历集合 -- foreachfor (String element : list) {System.out.println(element);}System.out.println("-----------------------------------------");//遍历集合 -- IteratorIterator<String> it = list.iterator();while(it.hasNext()){//判断是否有可迭代的元素String next = it.next();//获取下一个元素System.out.println(next);}System.out.println("-----------------------------------------");//遍历集合 -- ListIteratorListIterator<String> listIterator = list.listIterator();while(listIterator.hasNext()){//判断是否有可迭代的元素String next = listIterator.next();//获取下一个元素System.out.println(next);}} }
LinkedList独有的方法
//添加到头部list.addFirst("aaa");list.offerFirst("bbb");list.push("ccc");//添加到末尾list.addLast("xxx");list.offer("yyy");list.offerLast("zzz");System.out.println("获取第一个元素:" + list.element());System.out.println("获取第一个元素:" + list.getFirst());System.out.println("获取第一个元素:" + list.peek());System.out.println("获取第一个元素:" + list.peekFirst());System.out.println("获取第一个元素:" + list.pop());System.out.println("获取最后一个元素:" + list.getLast());System.out.println("获取最后一个元素:" + list.peekLast());//删除第一个元素list.poll();list.pollFirst();list.removeFirst();//删除最后一个元素list.pollLast();list.removeLast();//删除第一次出现的元素list.removeFirstOccurrence("abc");//删除最后一次出现的元素list.removeLastOccurrence("abc");//倒序遍历 // Iterator<String> descendingIterator = list.descendingIterator(); // while(descendingIterator.hasNext()){ // String next = descendingIterator.next(); // System.out.println(next); // }for (String element : list) {System.out.println(element);}
LikedList实现队列模式
import java.util.LinkedList; public class Test {// 注意:队列模式 - 先进先出 public static void main(String[] args) { LinkedList<String> list = new LinkedList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");while(!list.isEmpty()){//String element = list.pollFirst();String element = list.removeFirst();System.out.println(element);}System.out.println("集合的元素个数为:" + list.size());//0} }
4.LikedList实现队列模式
import java.util.LinkedList; public class Test { //注意:栈模式 - 先进后出/后进先出public static void main(String[] args) { LinkedList<String> list = new LinkedList<>(); list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee"); while(!list.isEmpty()){String element = list.removeLast();System.out.println(element);} System.out.println("集合的元素个数为:" + list.size());//0} }
2.Vector
Vector类从整个 Java 的集合发展历史来看,Vector算是一个元老级的类,在 JDK1.0 的时候就已经存在此类。但是到了Java2(JDK1.2)之后重点强调了集合框架的概念,所以先后定义了很多的新接口(如:List 等)。但是考虑到一大部分的人已经习惯了使用 Vector类,因此设计者就让 Vector 类多实现了一个 List接口,这样才将其保留下来。但是因为其是 List 接口的子类,所以 Vector 类的使用与之前的并没有太大的区别。但是Vector内部有一些比较老的方法名比较长的方法。
Vector的使用与LinkedList的使用基本一致
Vector老的方法
import java.util.Enumeration; import java.util.Vector; public class Test {public static void main(String[] args) { Vector<String> v = new Vector<>(); v.addElement("aaa");v.addElement("bbb");v.addElement("ccc");v.addElement("ddd");v.addElement("eee"); v.removeElementAt(0);//根据下标删除元素v.removeElement("bbb");//根据数据删除元素Enumeration<String> elements = v.elements();while(elements.hasMoreElements()){String nextElement = elements.nextElement();System.out.println(nextElement);}} }
3.Stack
Vector提供一个Stack子类,它用于模拟了“栈”这种数据结构,“栈”通常是指“后进先出”
import java.util.Stack; public class Test01 {// 继承关系:class Stack extends Vector// 特点:栈模式 public static void main(String[] args) { Stack<String> stack = new Stack<>(); //将元素添加到栈顶stack.push("aaa");stack.push("bbb");stack.push("ccc");stack.push("ddd");stack.push("eee"); System.out.println("获取栈顶元素:" + stack.peek());System.out.println("获取元素到栈顶的距离:" + stack.search("bbb"));//4 - 从1开始数//判断集合是否为空内容while(!stack.empty()){ //删除栈顶元素,并返回String pop = stack.pop();System.out.println(pop);}} }
4.HashSet
- HashSet的使用
import java.util.HashSet; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; public class Test {public static void main(String[] args) {HashSet<String> set = new HashSet<>();//添加数据set.add("aaa");set.add("bbb");set.add("ccc");set.add("ddd");set.add("eee");//获取元素个数int size = set.size();System.out.println("获取元素个数:" + size);//5HashSet<String> newSet1 = new HashSet<>();Collections.addAll(newSet1, "aaa","bbb","ccc","ccc");//利用集合工具类(Collections)批量添加元素set.addAll(newSet1);//将newSet1中所有的元素都添加到set集合里//清空集合里所有的元素//set.clear();System.out.println("判断集合中是否包含指定元素:" + set.contains("qqq"));//falseSystem.out.println("判断集合中是否包含指定集合:" + set.containsAll(newSet1));//true//没有-true,有-falseSystem.out.println("判断集合里是否没有元素:" + set.isEmpty());//falseset.remove("水菜丽");//通过数据删除元素set.removeAll(newSet1);//将set中有newSet1的元素全部删除(去除交集)HashSet<String> newSet2 = new HashSet<>();Collections.addAll(newSet2, "麻生希","水菜丽","樱井步");set.retainAll(newSet2);//将set中有newSet2的元素全部保留(保留交集)//将集合转换为数组Object[] array1 = set.toArray();System.out.println(Arrays.toString(array1));//[樱井步, 麻生希]//将集合转换为指定类型的数组String[] array2 = new String[2];set.toArray(array2);System.out.println(Arrays.toString(array2));//[樱井步, 麻生希]System.out.println("-----------------------------------------");//遍历集合 -- foreachfor (String element : set) {System.out.println(element);}System.out.println("-----------------------------------------");//遍历集合 -- IteratorIterator<String> it = set.iterator();while(it.hasNext()){//判断是否有可迭代的元素String next = it.next();//获取下一个元素System.out.println(next);}} }
HashSet的特点:无序且去重
添加步骤:
- 获取元素的hash值 – hashCode()
- 通过hash值计算在数组中的下标
- 判断下标上是否有元素
- 没有元素 – 直接添加
- 有元素 ---- 判断两个对象是否相同 hash && (==||equals())
- 相同 – 不添加数据(达到去重效果)
- 不相同 – 形成单向链表(JDK1.7头插法、JDK1.8尾插法)
遍历步骤:
遍历数组(顺序遍历)注意:添加步骤处理数据的逻辑和遍历步骤处理数据的逻辑不一样,导致无序
import java.util.HashSet; public class Test {public static void main(String[] args) {HashSet<String> set = new HashSet<>();set.add("aaa");set.add("bbb");set.add("ccc");set.add("ccc");set.add("Aa");set.add("BB"); for (String element : set) {System.out.println(element);}} }
5.LinkedHashSet
LinkedHashSet的使用(与HashSet的使用基本一致)
LinkedHashSet的特点
- 继承关系:class LinkedHashSet extends HashSet
- 特点:有序且去重
- 添加步骤:
- 在父类HashSet的基础上,添加的元素会存储上一个元素的地址,
- 上一个元素也会存储下一个元素的地址 – 双向链表
遍历步骤:
找到第一个元素,再向下依次找下一个元素import java.util.LinkedHashSet; public class Test {public static void main(String[] args) {LinkedHashSet<String> set = new LinkedHashSet<>();set.add("aaa");set.add("bbb");set.add("ccc");set.add("ccc");set.add("Aa");set.add("BB");for (String element : set) {System.out.println(element);}} }
6.TreeSet
TreeSet的使用(与HashSet的使用基本一致)
TreeSet的特点
特点:自然排序(TreeSet会根据不同的类型使用不同的排序规则)
import java.util.TreeSet; public class Test02 {public static void main(String[] args) { //TreeSet存储String -> 字典排序TreeSet<String> set1 = new TreeSet<>();set1.add("a");set1.add("c");set1.add("e");set1.add("bc");set1.add("bb"); for (String element : set1) {System.out.println(element);} System.out.println("-----------------------------"); //TreeSet存储Integer -> 数字升序TreeSet<Integer> set2 = new TreeSet<>(); set2.add(3);set2.add(5);set2.add(1);set2.add(2);set2.add(4); for (Integer element : set2) {System.out.println(element);}} }
7.比较器
内置比较器示例:
1.Student.class
public class Student implements Comparable<Student>{private String name;private char sex;private int age;private String classId;private String id;public Student() {} public Student(String classId, String id) {this.classId = classId;this.id = id;} public Student(String name, char sex, int age, String classId, String id) {this.name = name;this.sex = sex;this.age = age;this.classId = classId;this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getClassId() {return classId;}public void setClassId(String classId) {this.classId = classId;}public String getId() {return id;}public void setId(String id) {this.id = id;}@Overridepublic boolean equals(Object obj) {if(this == obj){return true;} if(obj instanceof Student){Student stu = (Student) obj;if(classId.equals(stu.classId) && id.equals(stu.id)){return true;} }return false;}@Overridepublic String toString() {return name + "\t" + sex + "\t" + age + "\t" + classId + "\t" + id;}//排序规则:按照年龄排序@Overridepublic int compareTo(Student o) {return this.age - o.age;} }
2.Test.class
import java.util.TreeSet; public class Test {public static void main(String[] args) { TreeSet<Student> set = new TreeSet<>();set.add(new Student("张三", '男', 29, "2402", "001")); set.add(new Student("李四", '男', 23, "2402", "002")); for (Student stu : set) {System.out.println(stu);}} }
外置比较器实例:
import java.util.Comparator; import java.util.TreeSet; public class Test04 {public static void main(String[] args) {TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {//排序规则:按照名字长度排序,名字长度一致按照年龄排序@Overridepublic int compare(Student o1, Student o2) {if(o1.equals(o2)){return 0;}int nameLen1 = o1.getName().length();int nameLen2 = o2.getName().length();if(nameLen1 != nameLen2){return nameLen1 - nameLen2;}int age1 = o1.getAge();int age2 = o2.getAge();if(age1 != age2){return age1 - age2;}return 1;}});set.add(new Student("张三", '男', 29, "2402", "001")); set.add(new Student("李四", '男', 23, "2402", "002")); for (Student stu : set) {System.out.println(stu);}} }