1. 什么是集合:
- 集合与数组一样,可以保存一组元素,并且提供了操作数组元素的相关方法,使用更方便
2. java集合框架中相关接口:
- java.util.Collection接口:是所有集合的顶级接口,封装了所有集合所共有的东西,下面有多种实现类,因此我们有更多的数据结构可以选择。
- Collection接口下面有两种常见的子接口:
- java.util.List:线性表,是可以重复集合,并且有序
- java.util.Set:不可重复集合,大部分实现类是无序的
- 集合只能存放引用类型元素,并且存放的是元素的引用
3. Collection常用方法:
-
add():向集合中添加一个元素,成功添加则返回true
-
size():返回当前集合的元素个数
-
isEmpty():判断当前集合是否为空集.当且仅当size=0时返回true.
-
clear():清空集合
package apiday03; import java.util.ArrayList; import java.util.Collection; public class CollectionDemo { public static void main(String[] args) { Collection c = new ArrayList(); c.add("one"); //给集合添加元素 c.add("two"); c.add("three"); c.add("four"); c.add("five"); System.out.println(c); //Collection中重写了Object的toString()方法 int size = c.size(); //获取集合的元素个数 System.out.println("size:"+size); //5 boolean isEmpty = c.isEmpty(); //判断集合是否为空集(size为0表示为空集) System.out.println("是否为空集:"+isEmpty); //false c.clear(); //清空集合 System.out.println("集合已清空"); System.out.println(c); //[] System.out.println("size:"+c.size()); //0 System.out.println("是否为空集:"+c.isEmpty()); //true } }
-
contains():判断集合是否包含给定元素
-
remove():从集合中删除给定元素,成功删除返回true.
package apiday03; import java.util.ArrayList; import java.util.Collection; public class CollectionDemo { public static void main(String[] args) { Collection c = new ArrayList(); c.add(new Point(1,2)); c.add(new Point(3,4)); c.add(new Point(5,6)); c.add(new Point(7,8)); c.add(new Point(9,0)); c.add(new Point(1,2)); /* 集合重写了Object的toString()方法,格式如下: [元素1.toString(), 元素2.toString(), 元素3.toString(), ...] */ System.out.println(c); Point p = new Point(1,2); /* boolean contains(Object o) 判断当前集合是否包含给定元素,判断依据是给定元素是否与集合元素存在equals比较为true的情况 */ boolean contains = c.contains(p); System.out.println("是否包含:"+contains); //true /* boolean remove(Object o) 从集合中删除与给定元素equals比较为true的元素,若存在重复元素则只删除一次 */ c.remove(p); System.out.println(c); } } package apiday03; import java.util.Objects; /** * 点 */ public class Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } @Override public String toString() { return "(" + x + "," + y + ")"; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Point point = (Point) o; return x == point.x && y == point.y; } @Override public int hashCode() { return Objects.hash(x, y); } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } } package apiday03; import java.util.ArrayList; import java.util.Collection; /** * 集合是存放的是元素的引用 */ public class CollectionDemo3 { public static void main(String[] args) { Collection c = new ArrayList(); Point p = new Point(1,2); c.add(p); //将p添加到集合c中 System.out.println("p:"+p); //(1,2) System.out.println("c:"+c); //[(1,2)] p.setX(100); System.out.println("p:"+p); //(100,2) System.out.println("c:"+c); //[(100,2)] } }
-
addAll():将参数给定的集合中的所有元素添加到当前集合中,添加后当前集合发生改变则返回true
-
containsAll():判断当前集合中是否包含参数集合中的所有元素
-
retainAll():取交集
-
removeAll():删交集
package apiday03; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; /** * 集合间操作的演示 */ public class CollectionDemo2 { public static void main(String[] args) { Collection c1 = new ArrayList(); c1.add("java"); c1.add("c++"); c1.add(".net"); System.out.println("c1:"+c1); //[java, c++, .net] Collection c2 = new ArrayList(); c2.add("android"); c2.add("ios"); c2.add("java"); System.out.println("c2:"+c2); //[android, ios, java] /** * boolean addAll(Collection c) * 将参数给定的集合中的所有元素添加到当前集合中,添加后当前集合发生改变则返回true */ c1.addAll(c2); //将c2添加到c1中 System.out.println("c1:"+c1); //[java, c++, .net, android, ios, java] System.out.println("c2:"+c2); //[android, ios, java] Collection c3 = new ArrayList(); c3.add("c++"); c3.add("android"); c3.add("php"); System.out.println("c3:"+c3); //[c++, android, php] /* boolean containsAll(Collection c) 判断当前集合中是否包含参数集合中的所有元素 */ boolean contains = c1.containsAll(c3); //判断c1中是否包含c3 System.out.println("包含所有:"+contains); //取交集,c1中仅保留c1与c3的共有元素,c3不变 //c1.retainAll(c3); //System.out.println("c1:"+c1); //[c++, android] //System.out.println("c3:"+c3); //[c++, android, php] //删交集,将c1中与c3的共有元素删除,c3不变 c1.removeAll(c3); System.out.println("c1:"+c1); //[java, .net, ios, java] System.out.println("c3:"+c3); //[c++, android, php] } }
4. 集合的遍历:
-
Collection接口提供了统一的遍历集合的方式:迭代器模式。通过iterator()方法可以获取一个用于遍历当前集合元素的迭代器(Iterator接口)。
-
java.util.Iterator接口:定义了迭代器遍历集合的相关操作。不同的集合都实现了用于遍历自身元素的迭代器实现类,我们无需记住它们的名字,从多态的角度把它们看成Iterator即可。
-
迭代器遍历遵循的步骤为:问、取、删,其中删除元素并不是必要操作
package apiday03; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * 集合的遍历: */ public class IteratorDemo { public static void main(String[] args) { Collection c = new ArrayList(); c.add("one"); c.add("#"); c.add("two"); c.add("#"); c.add("three"); c.add("#"); c.add("four"); c.add("#"); c.add("five"); System.out.println(c); //[one, #, two, #, three, #, four, #, five] /* 迭代器的常用方法: 1)boolean hasNext()-------问 询问集合是否还有"下一个"元素可供迭代 注意:迭代器默认开始位置是在集合第1个元素之前 无论调用多少次hasNext()方法,迭代器的位置都不会变 2)Object next()-----------取 迭代器向后移动一个位置来指向集合的下一个元素并将其获取 */ Iterator it = c.iterator(); //获取集合c的迭代器 while(it.hasNext()){ //若有下一个元素 String str = (String)it.next(); //获取下一个元素 if("#".equals(str)){ //若str为#号 //c.remove(str); //迭代器遍历过程中不能通过集合方法增删元素,否则会抛出异常 it.remove(); //删除next()方法所取的元素 } System.out.println(str); } System.out.println(c); } }
5. 增强型for循环:
-
JDK1.5时推出了一个特性:增强型for循环,也称为新循环,让我们使用相同的语法遍历集合和数组。
-
语法:
for(元素类型 变量名 : 集合或数组){ 循环体 }
package apiday03; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * 增强型for循环:新循环 */ public class NewForDemo { public static void main(String[] args) { String[] array = {"one","two","three","four","five"}; for(int i=0;i<array.length;i++){ System.out.println(array[i]); } //新循环遍历数组---会被编译器改回普通的for循环 for(String str : array){ System.out.println(str); } Collection c = new ArrayList(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); Iterator it = c.iterator(); while(it.hasNext()){ String str = (String)it.next(); System.out.println(str); } //新循环遍历集合---会被编译器改回迭代器遍历 for(Object obj : c){ String str = (String)obj; System.out.println(str); } } }
6. 泛型:
-
JDK1.5时推出了一个特性:泛型
-
泛型也称为参数化类型,允许我们在使用一个类时,传入某个类型来规定其内部的属性、方法参数或返回值类型,使得我们使用的时候更加方便。
- 泛型在集合中被广泛使用,用来指定集合中元素的类型
- 若不指定泛型的具体类型,则默认为Object,获取泛型的值时,编译器会补充强转操作。
package apiday03; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * 泛型的演示 */ public class GenericDemo { public static void main(String[] args) { Collection<String> c = new ArrayList<>(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); //c.add(123); //编译错误,参数类型违背了集合c所指定的泛型E的实际类型String //迭代器所指定的泛型应当与其遍历的集合的泛型一致 Iterator<String> it = c.iterator(); while(it.hasNext()){ String str = it.next(); //指定泛型后,获取元素无需再手动强转 System.out.println(str); } for(String str : c){ System.out.println(str); } } }
7. 集合与数组的转换:
-
数组转换为List集合:
package apiday03; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * 数组转换为集合: * 数组的工具类java.util.Arrays提供了一个静态方法:asList() * 该方法可以将一个数组转换为一个List集合 */ public class ArrayToListDemo { public static void main(String[] args) { String[] array = {"one","two","three","four","five"}; System.out.println("array:"+ Arrays.toString(array)); //asList()方法会返回内部类ArrayList,该ArrayList内部直接引用给定数组array List<String> list = Arrays.asList(array); System.out.println("list:"+list); //对数组操作后,集合也会做相应的改变 array[1] = "six"; System.out.println("array:"+Arrays.toString(array)); System.out.println("list:"+list); //对集合操作后,数组也会做相应的改变-----明天讲操作List集合 //添加元素/删除元素相当于要往数组中加元素/减元素, //而数组是定长的,不会自动扩容/缩容的,因此会发生不支持操作的异常 //list.add("!!!!!"); //运行时发生不支持操作的异常 //如果我们需要增删元素,可另行创建一个集合同时包含list集合的元素即可 List<String> list2 = new ArrayList<>(list); //等同于先new再addAll() System.out.println("list2:"+list2); list2.add("!!!!!"); System.out.println("list2:"+list2); } }
-
集合转为数组:
package apiday03; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; /** * 集合转换为数组 * Collection提供了一个方法:toArray,可以将当前集合转换为一个数组 */ public class CollectionToArrayDemo { public static void main(String[] args) { Collection<String> c = new ArrayList<>(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); System.out.println(c); //若参数数组元素个数==集合元素个数,那就正常转换 //若参数数组元素个数>集合元素个数,则正常转换,同时末尾补默认值 //若参数数组元素个数<集合元素个数,则会按照集合大小给数组 String[] array = c.toArray(new String[0]); System.out.println(Arrays.toString(array)); } }
8. List接口:
-
继承自Collection接口,List集合是可重复集合,并且有序,并且提供了一套可以通过下标操作元素的方法
-
常见的实现类:
-
java.util.ArrayList:内部使用数组实现,查询性能更好(直接下标查找)、增删性能不太好
-
java.util.LinkedList:内部使用链表实现,查询性能不太好,首尾增删元素性能更好
注意:在对集合操作的性能没有特别苛刻要求时,通过选择ArrayList。
-
9. List集合常见方法:
-
get():根据下标获取元素
-
set():将指定元素设置到指定位置 ,并返回被替换的元素(用时接收)
-
重载add():将指定元素添加到指定位置,理解为插入操作
-
重载remove():删除并返回指定位置元素
package apiday04; import java.util.*; /** * List集合: * 1.List接口中提供了一套可以通过下标操作元素的方法 */ public class ListDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("one"); list.add("two"); list.add("three"); list.add("four"); list.add("five"); System.out.println("list:"+list.toString()); /* E get(int index): 获取指定下标所对应的元素 */ String e = list.get(2); System.out.println(e); //three for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); } for(String s : list){ System.out.println(s); } Iterator<String> it = list.iterator(); while(it.hasNext()){ System.out.println(it.next()); } System.out.println("----------------------------------"); /* E set(int index, E e) 将给定元素设置到指定位置,返回被替换的元素 */ String old = list.set(2,"six"); //将list中下标为2的元素设置为six //list.set(2,"six"); //常规用法 System.out.println(list); //[one, two, six, four, five] System.out.println(old); /* java.util.Collections为集合的工具类,包含了集合相关的静态方法 */ Collections.reverse(list); //反转list集合元素(下标变化了) System.out.println(list); //[five, four, six, two, one] /* * void add(int index, E e) * 将给定元素e添加到index所指定的位置,相当于插入操作 */ list.add(3,"three"); System.out.println(list); //[five, four, six, three, two, one] /* E remove(int index) 删除指定位置元素,并返回指定位置元素 */ String o = list.remove(2); //list.remove(2); //常规操作 System.out.println(list); //[five, four, three, two, one] System.out.println(o); //six } }
-
subList():获取当前集合中指定范围内的子集(含头不含尾)
package apiday04; import java.util.ArrayList; import java.util.List; /** * List提供了获取子集的操作: * List subList(int start,int end): 含头不含尾 */ public class ListDemo2 { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); for(int i=0;i<10;i++){ list.add(i*10); //自动装箱 } System.out.println(list); //[0, 10, 20, 30, 40, 50, 60, 70, 80, 90] //获取下标3到7的子集 List<Integer> subList = list.subList(3,8); System.out.println(subList); //[30, 40, 50, 60, 70] //将子集每个元素都扩大10倍 for(int i=0;i<subList.size();i++){ subList.set(i,subList.get(i)*10); } System.out.println(subList); //[300, 400, 500, 600, 700] //注意:对子集的操作就是对原集合对应元素操作 System.out.println(list); //[0, 10, 20, 300, 400, 500, 600, 700, 80, 90] list.remove(0); System.out.println(list); //[10, 20, 300, 400, 500, 600, 700, 80, 90] //原集合修改之后,子集将不能再进行操作了,操作则发生异常,但是可以重新获取子集 //System.out.println(subList); //发生不支持修改异常 } }
10. 集合的排序:
-
Collections是集合的工具类,里面定义了很多静态方法用于操作集合
package apiday04; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; /** * 集合的排序 */ public class SortListDemo { public static void main(String[] args) { Random rand = new Random(); List<Integer> list = new ArrayList<>(); for(int i=0;i<10;i++){ list.add(rand.nextInt(100)); } System.out.println("list原始数据:"+list); Collections.sort(list); //自然排序(从小到大) System.out.println("list排序后数据:"+list); Collections.reverse(list); //反转list集合(数据已经变化了) System.out.println("list反转后:"+list); } }
-
Collections.sort(List list)方法:可以对list集合进行自然排序(从小到大),Collections.sort(List list)方法要求List集合中的元素必须是可比较的,若不可比较则直接发生编译错误,不允许排序。判定是否可比较的标准为元素是否实现了java.util.Comparable接口。实际开发中,我们并不会让我们自己定义的类去实现Comparable接口的,因为这对我们的程序有侵入性。
侵入性:当我们调用某个API功能时,其要求我们为其修改其它额外的代码,这个现象叫做侵入性。侵入性越强则越不利于程序的后期维护,应尽量避免。
-
重载的Collections.sort(List list, Comparator c)方法,可以通过Comparator来自定义规则
package apiday04; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * 字符串的排序 */ public class SortListDemo2 { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("广东马化云"); list.add("科比afsadsfsdaf"); list.add("布莱恩特"); System.out.println("list原始数据:"+list); //自定义排序规则: Collections.sort(list, new Comparator<String>() { /* compare()方法用于定义o1和o2比较大小的规则,并用返回值表达大小关系 返回值实现的要求:-------不用纠结,去记下面的结论 1)如果返回值>0则表达的是o1>o2 2)如果返回值<0则表达的是o1<o2 3)如果返回值=0则表达的是o1=o2 结论: 1)前面的-后面的----------升序 2)后面的-前面的----------降序 */ public int compare(String o1, String o2) { return o1.length()-o2.length(); //升序 //return o2.length()-o1.length(); //降序 } }); System.out.println("list排序后数据:"+list); /* List<String> list = new ArrayList<>(); list.add("jack"); list.add("rose"); list.add("tom"); list.add("black"); list.add("jerry"); list.add("Kobe"); System.out.println("list原始数据:"+list); //对英文字符串排序时,会按首字母的ASCII码排序 //若首字母相同,则比较第2个字符的ASCII码,以此类推 Collections.sort(list); System.out.println("list排序后数据:"+list); */ } } package apiday04; import java.util.Objects; /** * 点 */ public class Point{ private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } @Override public String toString() { return "(" + x + "," + y + ')'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Point point = (Point) o; return x == point.x && y == point.y; } @Override public int hashCode() { return Objects.hash(x, y); } } package apiday04; import java.util.ArrayList; import java.util.Comparator; import java.util.List; /** * 排序自定义类型 */ public class SortListDemo3 { public static void main(String[] args) { List<Point> list = new ArrayList<>(); list.add(new Point(5,8)); list.add(new Point(15,60)); list.add(new Point(56,50)); list.add(new Point(1,4)); list.add(new Point(9,6)); list.add(new Point(99,88)); System.out.println(list); /* Collections.sort(list, new Comparator<Point>() { public int compare(Point o1, Point o2) { int len1 = o1.getX()*o1.getX()+o1.getY()*o1.getY(); int len2 = o2.getX()*o2.getX()+o2.getY()*o2.getY(); return len1-len2; //升序 //return len2-len1; //降序 //return o1.getX()-o2.getX(); //按x坐标升序 //return o2.getY()-o1.getY(); //按y坐标降序 } }); System.out.println(list); */ //jdk1.8,List集合自身提供了sort方法进行排序,sort方法依然需要传入比较器 list.sort(new Comparator<Point>() { public int compare(Point o1, Point o2) { int len1 = o1.getX()*o1.getX()+o1.getY()*o1.getY(); int len2 = o2.getX()*o2.getX()+o2.getY()*o2.getY(); return len1-len2; //升序 //return len2-len1; //降序 } }); System.out.println(list); } }
11. Set接口:
-
继承自Collection接口,元素是不可重复的,并且是无序的
-
常见的实现类:
-
HashSet类:
package apiday04; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Set集: 不可重复集合、并且无序 */ public class SetDemo { public static void main(String[] args) { //小面试题: 如何去重? List<String> list = new ArrayList<>(); list.add("one"); list.add("two"); list.add("three"); list.add("four"); list.add("five"); list.add("two"); System.out.println(list); Set<String> set = new HashSet<>(); set.addAll(list); System.out.println(set); /* Set<String> set = new HashSet<>(); set.add("one"); set.add("two"); set.add("three"); set.add("four"); set.add("five"); set.add("two"); set.add("five"); System.out.println(set); */ } }
-