一、迭代器
1.Iterator
概念:Iterator是一个接口,它是集合的迭代器,集合可以通过Iterator去遍历集合中的元素,常用API接口:
- hasNext():如果迭代器中还有元素,则返回true。
- next():返回迭代器中的下一个元素。
- remove():删除迭代器新返回的元素。
案例:使用Iterator遍历元素
javapublic 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"时删除该元素
javaimport 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遍历元素
javaimport 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"时删除
javapublic 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"
javaimport 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"
javaimport 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指定下标遍历元素
javapublic 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倒序遍历元素
javaimport 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.泛型限定
案例及解析:
javaimport java.util.ArrayList; public class Test { //继承关系:Object.A.B public 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.泛型的使用
接口中使用泛型
javapublic interface IManagerSystem<T> { public void add(T t); public void delete(T t); public ArrayList<T> query(); }
类中使用泛型
javapublic class MyArrayList<E>{ public void add(E e){} public void remove(E e){} }
三、集合(续)
1.LinkedList
使用
javaimport 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"));//true System.out.println("判断集合中是否包含指定集合:" + list.containsAll(newList1));//true System.out.println("获取元素在集合中第一次出现的下标:" + list.indexOf("ccc"));//12 System.out.println("获取元素在集合中最后一次出现的下标:" + list.lastIndexOf("ccc"));//13 //没有-true,有-false System.out.println("判断集合里是否没有元素:" + list.isEmpty());//false list.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("-----------------------------------------"); //遍历集合 -- foreach for (String element : list) { System.out.println(element); } System.out.println("-----------------------------------------"); //遍历集合 -- Iterator Iterator<String> it = list.iterator(); while(it.hasNext()){//判断是否有可迭代的元素 String next = it.next();//获取下一个元素 System.out.println(next); } System.out.println("-----------------------------------------"); //遍历集合 -- ListIterator ListIterator<String> listIterator = list.listIterator(); while(listIterator.hasNext()){//判断是否有可迭代的元素 String next = listIterator.next();//获取下一个元素 System.out.println(next); } } }
LinkedList独有的方法
java//添加到头部 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实现队列模式
javaimport 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实现队列模式
javaimport 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老的方法
javaimport 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子类,它用于模拟了"栈"这种数据结构,"栈"通常是指"后进先出"
javaimport 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的使用
javaimport 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);//5 HashSet<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"));//false System.out.println("判断集合中是否包含指定集合:" + set.containsAll(newSet1));//true //没有-true,有-false System.out.println("判断集合里是否没有元素:" + set.isEmpty());//false set.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("-----------------------------------------"); //遍历集合 -- foreach for (String element : set) { System.out.println(element); } System.out.println("-----------------------------------------"); //遍历集合 -- Iterator Iterator<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尾插法)
遍历步骤:
遍历数组(顺序遍历)
注意:添加步骤处理数据的逻辑和遍历步骤处理数据的逻辑不一样,导致无序
javaimport 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的基础上,添加的元素会存储上一个元素的地址,
- 上一个元素也会存储下一个元素的地址 -- 双向链表
遍历步骤:
找到第一个元素,再向下依次找下一个元素
javaimport 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会根据不同的类型使用不同的排序规则)
javaimport 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
javapublic 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; } @Override public 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; } @Override public String toString() { return name + "\t" + sex + "\t" + age + "\t" + classId + "\t" + id; } //排序规则:按照年龄排序 @Override public int compareTo(Student o) { return this.age - o.age; } }
2.Test.class
javaimport 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); } } }
外置比较器实例:
javaimport java.util.Comparator; import java.util.TreeSet; public class Test04 { public static void main(String[] args) { TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() { //排序规则:按照名字长度排序,名字长度一致按照年龄排序 @Override public 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); } } }