java学习笔记10——集合框架
枚举类的使用
Collection接口继承树
Map接口继承树
Collection 接口方法
总结:
集合框架概述 1.内存层面需要针对于多个数据进行存储。此时,可以考虑的容器有:数组、集合类2.数组存储多个数据方面的特点:> 数组一旦初始化,其长度就是确定的。> 数组中的多个元素是依次紧密排列的,有序的,可重复的> (优点)数组一旦初始化完成,其元素的类型就是确定的。不是此类型的元素,就不能添加到此数组中。int[] arr = new int[10];arr[0]= 1;arr[1]="AA";//编译报错Object[] arr1 = new Object[10];arr1[0] = new String();arr1[1] = new Date();> (优点)元素的类型既可以是基本数据类型,也可以是引用数据类型数组存储多个数据方面的弊端:> 数组一旦初始化,其长度就不可变了。> 数组中存储数据特点的单一性。对于无序的、不可重复的场景的多个数据就无能为力了。> 数组中可用的方法、属性都极少。具体的需求,都需要自己来组织相关的代码逻辑。> 针对于数组中元素的删除、插入操作,性能较差。3.Java集合框架体系(java.util包下) java.util.Collection:存储一个一个的数据|-----子接口:List:存储有序的、可重复的数据 ("动态"数组)|---- ArrayList(主要实现类)、LinkedList、Vector|-----子接口:Set:存储无序的、不可重复的数据 (高中学习的集合)|----HashSet(主要实现类)、LinkedHashSet、TreeSet java.util.Map:存储一对一对的数据(key-value键值对,(x1,y1)、(x2,y2) --> y=f(x),类似于高中的函数)|---- HashMap(主要实现类)、LinkedHashMap、TreeMap、Hashtable、Properties4.学习的程度把握 层次1:针对于具体特点的多个数据,知道选择相应的适合的接口的主要实现类,会实例化,会调用常用的方法。 层次2:区分接口中不同的实现类的区别。 ********************************** 层次3:① 针对于常用的实现类,需要熟悉底层的源码 ② 熟悉常见的数据结构(第14章讲)总结2:Collection中的常用方法
1.常用方法:(Collection中定义了15个抽象方法。这些方法需要大家熟悉!) add(Object obj) addAll(Collection coll) clear() isEmpty() size() contains(Object obj) containsAll(Collection coll) retainAll(Collection coll) remove(Object obj) removeAll(Collection coll) hashCode() equals() toArray() ************* iterator()2.集合与数组的相互转换: 集合 ---> 数组:toArray() 数组 ---> 集合:调用Arrays的静态方法asList(Object... objs) 3.向Collection中添加元素的要求:要求元素所属的类一定要重写equals()! 原因: 因为Collection中的相关方法(比如:contains() / remove())在使用时,要调用元素所在类的equals()
相关代码:测试Collection中一些相关方法的使用
public class CollectionTest {/*** (1)add(Object obj):添加元素对象到当前集合中* (2)addAll(Collection other):添加other集合中的所有元素对象到当前集合中,即this = this U other*/@Testpublic void test1(){Collection coll = new ArrayList();//add()coll.add("AA");coll.add(123); //自动装箱coll.add("尚硅谷");coll.add(new Object());coll.add(new Person("Tom",12));System.out.println(coll);//addAll(Collection other)Collection coll1 = new ArrayList();coll1.add("BB");coll1.add(456);System.out.println(coll.size());coll.addAll(coll1); //[AA, 123, 尚硅谷, java.lang.Object@36d64342, Person{name='Tom', age=12}, BB, 456]
// coll.add(coll1); // [AA, 123, 尚硅谷, java.lang.Object@511baa65, Person{name='Tom', age=12}, [BB, 456]]System.out.println(coll);//size():System.out.println(coll.size());}/*** (3)int size():获取当前集合中实际存储的元素个数* (4)boolean isEmpty():判断当前集合是否为空集合* (5)boolean contains(0bject obj):判断当前集合中是否存在一个与obj对象equals返回true的元素* (6)boolean containsAll(Collection coll):判断col集合中的元素是否在当前集合中都存在。即col集合是否是当前集合的“子集”* (7)boolean equals(0bject obj):判断当前集合与obj是否相等*/@Testpublic void test2(){Collection coll = new ArrayList();//add()coll.add("AA");Person p1 = new Person("Tom",12);coll.add(p1);coll.add(128); //自动装箱coll.add("尚硅谷");coll.add(new Object());//isEmpty()System.out.println(coll.isEmpty()); //false//contains(0bject obj)System.out.println(coll.contains("AA")); //trueSystem.out.println(coll.contains(128)); //trueSystem.out.println(coll.contains(new String("尚硅谷")));//trueSystem.out.println(coll.contains(new Person("Tom",12))); //false ---> 重写后为true//containsAll(Collection coll)Collection coll1 = new ArrayList();//add()coll1.add("AA");coll1.add(128); //true
// coll1.add("BB"); //falseSystem.out.println(coll.containsAll(coll1));}/*** (8)void clear():清空集合元素* (9)boolean remove(0bject obj):从当前集合中删除第一个找到的与obj对象equals返回true的元素。* (10)boolean removeAll(Collection coll):从当前集合中删除所有与col集合中相同的元素。即this = this-this ∩ coll* (11)boolean retainAll(collection coll):从当前集合中删除两个集合中不同的元素,使得当前集合仅保留与coll集合中的元素相同的元素,* 即当前集合中仅保留两个集合的交集,即this=this ∩ coll;* 注意几种删除方法的区别*/@Testpublic void test3(){Collection coll = new ArrayList();//add()coll.add("AA");coll.add("AA");Person p1 = new Person("Tom",12);coll.add(p1);coll.add(128); //自动装箱coll.add(new String("尚硅谷"));
// coll.clear();
// System.out.println(coll);//[]
// System.out.println(coll.size()); //0//remove(Object obj)
// coll.remove(p1);
// coll.remove(new Person("Tom",12)); //能删除,已经被重写过coll.remove("AA"); //只删除一个System.out.println(coll);}/*** (12)Object[] toArray():返回包含当前集合中所有元素的数组* (13)hashCode():获取集合对象的哈希值* (14)iterator():返回迭代器对象,用于集合遍历*/@Testpublic void test4(){Collection coll = new ArrayList();//add()coll.add("AA");coll.add("AA");Person p1 = new Person("Tom",12);coll.add(p1);coll.add(128); //自动装箱coll.add(new String("尚硅谷"));//集合 ---> 数组Object[] arr = coll.toArray();System.out.println(Arrays.toString(arr));}@Testpublic void test5(){String[] arr = new String[]{"AA","BB","CC"};Collection list = Arrays.asList(arr);System.out.println(list); //[AA, BB, CC]List list1 = Arrays.asList("AA","BB","CC");System.out.println(list1.size()); //[AA, BB, CC] 3}@Testpublic void test6(){Integer[] arr = new Integer[]{1,2,3};List list = Arrays.asList(arr);System.out.println(list.size()); //3System.out.println(list); //[1, 2, 3]int[] arr1 = new int[]{1,2,3};List list1 = Arrays.asList(arr1);System.out.println(list1.size()); //1System.out.println(list1); //[[I@7f63425a]}
}Person
public class Person {String name;int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("Person equals()...");if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age && Objects.equals(name, person.name);}
}
Iterator迭代器接口
总结:
1.迭代器(Iterator)的作用? 用来遍历集合元素的。 2.如何获取选代器(Iterator)对象? Iterator iterator = coll.iterator(); 3.如何实现遍历(代码实现) while(iterator.hasNext()){System.out.println(iterator.next());//next():①指针下移 ② 将下移以后集合位置上的元素返回 } 4.增强for循环(foreach循环)的使用(jdk5.0新特性) 4.1 作用 用来遍历数组、集合。 4.2 格式: for(要遍历的集合或数组元素的类型 临时变量 : 要遍历的集合或数组变量){操作临时变量的输出 } 4.3 说明: > 针对于集合来讲,增强for循环的底层仍然使用的是选代器。 > 增强for循环的执行过程中,是将集合或数组中的元素依次赋值给临时变量,注意,循环体中对临时变量的修改,可能不会导致原有集合或数组中元素的修改。
相关代码:
public class IteratorTest {@Testpublic void test1(){Collection coll = new ArrayList();//add()coll.add("AA");coll.add("AA");Person p1 = new Person("Tom",12);coll.add(p1);coll.add(128); //自动装箱coll.add(new String("尚硅谷"));//获取迭代器对象Iterator iterator = coll.iterator();
// System.out.println(iterator.getClass());//方式1:
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next());
// System.out.println(iterator.next()); //如果超出了集合中元素的个数,会报NoSuchElementException异常信息//方式2:
// for (int i = 0; i < coll.size(); i++) {
// System.out.println(iterator.next());
// }//方式3:推荐while(iterator.hasNext()){System.out.println(iterator.next());};}@Testpublic void test2(){Collection coll = new ArrayList();//add()coll.add("AA");coll.add("BB");Person p1 = new Person("Tom",12);coll.add(p1);coll.add(128); //自动装箱coll.add(new String("尚硅谷"));//方式1:错误的遍历/*** BB* 128* 报错NoSuchElementException*/
// Iterator iterator = coll.iterator();
// while(iterator.next() != null){
// System.out.println(iterator.next());
// }/*** AA* ...* ...*///方式2:错误的遍历//每次调用coll.iterator(),都会返回一个新的迭代器对象while(coll.iterator().hasNext()){System.out.println(coll.iterator().next());}}
}2.ForTest
public class ForTest {@Testpublic void test(){Collection coll = new ArrayList();//add()coll.add("AA");coll.add("BB");Person p1 = new Person("Tom",12);coll.add(p1);coll.add(128); //自动装箱coll.add(new String("尚硅谷"));for(Object obj : coll){System.out.println(obj);}}@Testpublic void test2(){int[] arr = new int[]{1,2,3,4,5};for(int i : arr){System.out.println(i);}String[] str = new String[]{"GG","JJ","DD","MM","SS"};for(String s : str){System.out.println(s);}}
}
面试题:
public class InterviewTest {@Testpublic void testFor(){String[] arr1 = new String[]{"AA","CC","DD"};//赋值操作1
// for(int i = 0; i < arr1.length; i++){
// arr1[i] = "MM";
// }//赋值操作2,两个都是把地址传递过来,但是这个地方是把地址赋给新的变量,然后更改这个新的变量for(String s : arr1){s = "MM";}//遍历for(String s : arr1){System.out.println(s);}}
}
Collection子接口之一:List接口
List实现类之一:ArrayList
List实现类之二:LinkedList
List 实现类之三:Vector
总结:
1.List接口中存储数据的特点: 用于存储有序的、可以重复的数据。---> 使用List替代数组,"动态"数组 2.List中的常用方法 第1波:Collection中声明的15个方法,第2波: 因为List是有序的,进而就有索引,进而就会增加一些针对索引操作的方法。 - 插入元素- void add(int index,Object ele):在index位置插入ele元素- boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来 - 获取元素- Object get(int index):获取指定index位置的元素- List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合 - 获取元素索引- int index0f(Object obj):返回obj在集合中首次出现的位置- int lastIndex0f(Object obj):返回obj在当前集合中末次出现的位置 - 删除和替换元素- Object remove(int index):移除指定index位置的元素,并返回此元素- Object set(int index, Object ele):设置指定index位置的元素为ele 小结:增add(Object obj)addAll(Collection coll)删remove(Object obj)remove(int index)改set(int index, Object ele)查get(int index)插add(int index,Object ele)addAll(int index,Collection eles)长度size()遍历iterator():使用迭代器进行遍历增强for循环一般的for循环3.List及其实现类特点 java.util.Collection:存储一个一个的数据|-----子接口:List:存储有序的、可重复的数据 ("动态"数组)|---- ArrayList: List的主要实现类,线程不安全的、效率高,底层使用Object[]数组存储在添加数据、查找数据时(O(1)),效率较高;在插入、删除数据时,效率较低 (O(n))|---- LinkedList:底层使用双向链表的方式进行存储,在对集合中的数据进行频繁的删除、插入操作时,建议使用此类在插入、删除数据时(O(1)),效率较高;在添加数据、查找数据时(O(n)),效率较低|---- Vector: List的古老实现类,线程安全的、效率低,底层使用Object[]数组存储在插入和删除数据的时候,对于ArrayList类而言,会影响到当前索引的后面元素,而对于LinkedList这种双向链表来说却不会影响到很多元素,只是改变周围元素的指向,双向链表是通过指针连接的 [面试题] ArrayList、Vector的区别? ArrayList、LinkedList的区别?
代码:
public class ListTest {/*** 增* add(Object obj)* addAll(Collection coll)* 删* remove(Object obj)* remove(int index)* 改* set(int index, Object ele)* 查* get(int index)* 插* add(int index,Object ele)* addAll(int index,Collection eles)* 长度* size()* 遍历* iterator():使用迭代器进行遍历* 增强for循环* 一般的for循环*/@Testpublic void test(){List list = new ArrayList();//add(Object obj)list.add("AA");list.add("BB");list.add(123); //自动装箱list.add(new Person("Tom",12));System.out.println(list.toString());// add(int index,Object ele)list.add(2,"CC");System.out.println(list);
// addAll(int index,Collection eles)List list1 = Arrays.asList(1,2,3);list.addAll(1,list1); //[AA, 1, 2, 3, BB, CC, 123, Person{name='Tom', age=12}]//将list1整体作为一个元素,插入到索引1的位置
// list.add(1,list1); //[AA, [1, 2, 3], BB, CC, 123, Person{name='Tom', age=12}]System.out.println(list);}@Testpublic void test2(){List list = new ArrayList();list.add("AA");list.add("BB");list.add(123); //自动装箱list.add(2); //自动装箱list.add(new Person("Tom",12));//删除索引2的元素
// list.remove(2);
// System.out.println(list);
// System.out.println(list.get(2));//删除数据2list.remove(Integer.valueOf(2));System.out.println(list);}@Testpublic void test3(){List list = new ArrayList();list.add("AA");list.add("BB");list.add(123); //自动装箱list.add(2); //自动装箱list.add(new Person("Tom",12));//遍历方式1:使用迭代器
// Iterator iterator = list.iterator();
// while(iterator.hasNext()){
// System.out.println(iterator.next());
// }//遍历方式2:增强for循环
// for (Object obj : list){
// System.out.println(obj);
// }//遍历方式3:一般的for循环for(int i = 0;i<list.size();i++){System.out.println(list.get(i));}}
}
Person
public class Person {String name;int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("Person equals()...");if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age && Objects.equals(name, person.name);}
}
练习题:
案例:键盘录入学生信息,保存到集合List中。 (1)定义学生类:属性为姓名、年龄,提供必要的getter、setter方法,构造器,toString(),equals()方法。 (2)使用ArrayList集合,保存录入的多个学生对象。 (3)循环录入的方式,1:继续录入,0:结束录入。 (4)录入结束后,用foreach遍历集合:StudentTest public class StudentTest {public static void main(String[] args) {Scanner scan = new Scanner(System.in);List list = new ArrayList();System.out.println("请录入学生信息:");//通过循环添加多个学生信息while(true) {System.out.println("1.继续录入,0.结束录入");int selection = scan.nextInt();if(selection == 0){break;}System.out.print("请输入学生的姓名:");String name = scan.next();System.out.print("请输入学生的年龄:");int age = scan.nextInt();Student s = new Student(name, age);list.add(s);}//遍历集合中的学生信息System.out.println("遍历学生信息");for(Object s : list){Student stu = (Student)s;System.out.println(stu.toString());}scan.close();} } Student public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}// @Override // public int hashCode() { // return Objects.hash(name, age); // } }
练习2
案例: 定义方法public static int listTest(Collection list,String s)统计集合中指定元素出现的次数 (1)创建集合,集合存放随机生成的30个小写字母 (2)用listTest统计,a、b、c、x元素的出现次数 (3)效果如下public class ListTest {public static void main(String[] args) {//需求1:随机生成30个字符,存放在ArrayList中ArrayList list = new ArrayList();for(int i = 0; i < 30; i++){//'a' - 'z' [97,122] (char)强制类型转换list.add((char)(Math.random() * (122-97 +1) + 97) + "");}System.out.println(list);//int aCount = listTest(list, "a");int bCount = listTest(list, "b");int cCount = listTest(list, "c");int xCount = listTest(list, "x");System.out.println(aCount);System.out.println(bCount);System.out.println(cCount);System.out.println(xCount);}//需求2:遍历ArrayList,查找指定的元素出现的次数public static int listTest(Collection list, String s){int count = 0;for(Object obj : list){if(s.equals(obj)){count++;}}return count;} }
练习3:
案例:KTV点歌系统【说明】 使用ArrayList集合,实现编写一个模拟KTV点歌系统的程序。在程序中, 指令1代表添加歌曲 指令2代表将所选歌曲置顶 指令3代表将所选歌曲提前一位, 指令4代表退出该系统。要求根据用户输入的指令完成相关的操作:【提示】 (1)显式界面如下: System.out.println("----------欢迎来到点歌系统------------"); System.out.println("1.添加歌曲至列表"); System.out.println("2.将歌曲置顶"); System.out.println("3.将歌曲前移一位"); System.out.println("4.退出");(2)程序中需要创建一个集合作为歌曲列表,并向其添加一部分歌曲public class KTVByArrayList {private static ArrayList musicList = new ArrayList();//创建歌单列表private static Scanner sc = new Scanner(System.in);public static void main(String[] args) {addMusicList(); //添加一部分歌曲至歌曲列表boolean flag = true;while (flag) {System.out.println("当前歌曲列表:" + musicList);System.out.println("------------欢迎来到点歌系统-----------");System.out.println("1.添加歌曲至列表");System.out.println("2.将歌曲置顶");System.out.println("3.将歌曲前移一位");System.out.println("4.退出");System.out.print("请输入操作序号:");int key = sc.nextInt(); //接收键盘输入的功能选项序号//执行序号对应的功能switch (key) {case 1://添加歌曲至列表addMusic();break;case 2://将歌曲置顶setTop();break;case 3://将歌曲前移一位setBefore();break;case 4://退出System.out.println("----------退出----------");System.out.println("您已退出系统");flag = false;break;default:System.out.println("----------------------");}}}//初始时添加歌曲名称public static void addMusicList() {musicList.add("本草钢目");musicList.add("你是我的眼");musicList.add("老男孩");musicList.add("白月光与朱砂痣");musicList.add("不谓侠");musicList.add("爱你");}//执行添加歌曲private static void addMusic() {System.out.print("请输入要添加的歌曲名称:");String musicName = sc.next();musicList.add(musicName); //添加歌曲到列表的最后System.out.println("已添加歌曲" + musicName);}//执行将歌曲置顶private static void setTop() {System.out.print("请输入要置顶的歌曲名称:");String musicName = sc.next(); //获取键盘输入内容int musicIndex = musicList.indexOf(musicName); //查找指定歌曲位置if(musicIndex < 0){ //判断歌曲是否存在System.out.println("当前列表中没有输入的歌曲!");}else if(musicIndex == 0){System.out.println("当前歌曲默认已置顶!");}else{musicList.remove(musicName); //移除指定的歌曲musicList.add(0,musicName); //将指定的歌曲放在第一位System.out.println("已将歌曲《"+musicName+"》置顶");}}//执行将歌曲置顶前一位private static void setBefore() {System.out.print("请输入要置前的歌曲名称:");String musicName = sc.next(); //获取键盘输入内容int musicIndex = musicList.indexOf(musicName); //查找指定歌曲位置if(musicIndex < 0){ //判断输入歌曲是否存在System.out.println("当前列表中没有输入的歌曲!");}else if(musicIndex == 0){ //判断歌曲是否已在第一位System.out.println("当前歌曲已在最顶部!");}else {musicList.remove(musicName); //移除指定的歌曲musicList.add(musicIndex - 1,musicName); //将指定的歌曲放在前一位System.out.println("已将歌曲《" + musicName + "》置前一位");}} }
面试题:
public class InterviewTest {@Testpublic void testListRemove(){List list = new ArrayList();list.add(1); //自动装箱
// list.add(2);list.add(128);list.add(3);updateList(list);System.out.println(list);//}private static void updateList(List list){
// list.remove(2); //删除的是索引2list.remove(Integer.valueOf(128)); //[1, 3]}
}
Collection子接口之二:Set接口
Set实现类之一:HashSet
Set实现类之二:LinkedHashSet
Set实现类之三:TreeSet
排 序—自然排序
排 序—定制排序
总结:
1.Set及其实现类特点 java.util.Collection:存储一个一个的数据|-----子接口:Set:存储无序的、不可重复的数据(高中学习的集合)|---- Hashset(主要实现类):底层使用的是HashMap,即使用数组+单向链表+红黑树结构进行存储。|---- LinkedHashSet:是HashSet的子类;在现有的数组+单向链表+红黑树结构的基础上,又添加了一组双向链表,用于记录添加元素的先后顺序。即:我们可以按照添加元素的顺序,实现遍历。便于我们频繁的查询操作|---- TreeSet:底层使用红黑树存储。可以按照添加的元素的指定的属性的大小顺序进行遍历。2.开发中的使用频率及场景: > 较List、Map来说,Set使用的频率比较少。 > 用来过滤重复数据3.Set中常用方法:即为Collection中声明的15个抽象方法,没有新增的方法4.Set中无序性、不可重复性的理解(以HashSet及其子类为例说明) > 无序性: != 随机性。添加元素的顺序和遍历元素的顺序不一致,是不是就是无序性呢? No!到底什么是无序性?与添加的元素的位置有关,不像ArrayList一样是依次紧密排列的。这里是根据添加的元素的哈希值,计算的其在数组中的存储位置。此位置不是依次排列的,表现为无序性。 > 不可重复性: 添加到Set中的元素是不能相同的。比较的标准,需要判断hashcode()得到的哈希值以及equals()得到的boolean型的结果。哈希值相同且equals()返回true,则认为元素是相同的。 5.添加到HashSet/LinkedHashSet中元素的要求:要求元素所在的类要重写两个方法:equals()和hashcode()同时,要求equals()和 hashcode()要保持一致性!我们只需要在IDEA中自动生成两个方法的重写即可,即能保证两个方法的一致性6.TreeSet的使用 6.1 底层的数据结构: 红黑树6.2 添加数据后的特点: 可以按照添加的元素的指定的属性的大小顺序进行遍历。 6.3向Treeset中添加的元素的要求: > 要求添加到TreeSet中的元素必须是同一个类型的对象,否则会报ClassCastException. > 添加的元素需要考虑排序:① 自然排序 ② 定制排序 6.4判断数据是否相同的标准 > 不再是考虑hashcode()和equals()方法了,也就意味着添加到TreeSet中的元素所在的类不需要重写hashCode()和equals()方法了 > 比较元素大小的或比较元素是否相等的标准就是考虑自然排序或定制排序中,compareTo()或compare()的返回值。如果compareTo()或compare()的返回值为0,则认为两个对象是相等的。由于TreeSet中不能存放相同的元素,则后一个相等的元素就不能添加到TreeSet中。
代码:
SetTest
public class SetTest {@Testpublic void test1(){/*** AA* BB* Person{name='Tom', age=12}* 123* false*/Set set = new HashSet();set.add("AA");set.add(123);set.add("BB");set.add(new Person("Tom",12));set.add(new Person("Tom",12));Iterator iterator = set.iterator();while (iterator.hasNext()){System.out.println(iterator.next());}System.out.println(set.contains(new Person("Tom",12))); //false}@Testpublic void test2(){/*** AA* 123* BB* Person{name='Tom', age=12}* false*/Set set = new LinkedHashSet();set.add("AA");set.add(123);set.add("BB");set.add(new Person("Tom",12));Iterator iterator = set.iterator();while (iterator.hasNext()){System.out.println(iterator.next());}System.out.println(set.contains(new Person("Tom",12))); //false}
}
Person
public class Person {String name;int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("Person equals()...");if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age && Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
代码2:
TreeSetTest
public class TreeSetTest {/*** 自然排序*/@Testpublic void test1(){/*** AA* CC* DD* GG* MM* SS*/TreeSet set = new TreeSet();set.add("CC");set.add("AA");set.add("DD");set.add("MM");set.add("GG");set.add("SS");
// set.add(123); //会报ClassCastException异常Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}/*** 自然排序*/@Testpublic void test2(){TreeSet set = new TreeSet();User u1 = new User("Tom",23);User u2 = new User("Jerry",43);User u3 = new User("Rose",13);User u4 = new User("Jack",23);User u5 = new User("Tony",33);set.add(u1);set.add(u2);set.add(u3);set.add(u4);set.add(u5);Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}/*** 定制排序*/@Testpublic void test3(){Comparator comparator = new Comparator(){/*** 按照姓名从小到大排序,如果姓名相同,继续比较age,按照从大到小的排列*/public int compare(Object o1, Object o2) {if(o1 instanceof User && o2 instanceof User){User u1 = (User)o1;User u2 = (User)o2;int value = u1.getName().compareTo(u2.getName());if(value != 0){return value;}return -(u1.getAge() - u2.getAge());}throw new RuntimeException("类型不匹配");}};TreeSet set = new TreeSet(comparator);User u1 = new User("Tom",23);User u2 = new User("Jerry",43);User u3 = new User("Rose",13);User u4 = new User("Jack",23);User u5 = new User("Tony",33);set.add(u1);set.add(u2);set.add(u3);set.add(u4);set.add(u5);Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}
}
User
public class User implements Comparable{private String name;private int age;public User() {}public User(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}// @Override
// public boolean equals(Object o) {
// System.out.println("User equals()...");
// if (o == null || getClass() != o.getClass()) return false;
// User user = (User) o;
// return age == user.age && Objects.equals(name, user.name);
// }
//
// @Override
// public int hashCode() {
// return Objects.hash(name, age);
// }/*** 按照年龄的从小到大排序* @param o the object to be compared.* @return*/
// @Override
// public int compareTo(@NotNull Object o) {
// if(this == o) {
// return 0;
// }
// if(o instanceof User){
// User u = (User)o;
// return this.age - u.age;
// }
// throw new RuntimeException("类型不匹配");
// }/*** 比如:先比较年龄从小到大排列,如果年龄相等,则继续比较姓名,从小到大*/@Overridepublic int compareTo(@NotNull Object o) {if(this == o) {return 0;}if(o instanceof User){User u = (User)o;int value = this.age - u.age;if(value != 0){return value;}return -this.name.compareTo(u.name);}throw new RuntimeException("类型不匹配");}
}
练习1
案例: 定义方法如下:public static List duplicateList(List list) 要求:① 参数List中只存放Integer的对象 ② 在List内去除重复数字值,尽量简单
代码:
public class Exer01 {public static void main(String[] args) {ArrayList list = new ArrayList();list.add(34);list.add(34);list.add(34);list.add(22);list.add(22);list.add(22);list.add(45);list.add(45);list.add(45);List newList = duplicateList(list);System.out.println(newList);}public static List duplicateList(List list) {//方式1: // HashSet set = new HashSet(); // for(Object obj : list){ // set.add(obj); // } // List list1 = new ArrayList(); // for(Object obj : set){ // list1.add(obj); // } // return list1;//方式2HashSet set = new HashSet(list);List list1 = new ArrayList(set);return list1;} }
练习2
案例: 编写一个程序,获取10个1至20的随机数,要求随机数不能重复。并把最终的随机数输出到控制台
代码:
/*** ClassName: Exero2* Package: com.atguigu04.set.exer2* Description:* 编写一个程序,获取10个1至20的随机数,要求随机数不能重复。并把最终的随机数输出到控制台* @Author: lwfstart* @Create 2025-03-31 13:25* @Version: 1.0*/ public class Exer02 {public static void main(String[] args) {Set set = new HashSet();while(set.size() < 10){int random = (int) (Math.random() * (20 - 1 + 1) + 1);set.add(random);}Iterator iterator = set.iterator();while(iterator.hasNext()){System.out.println(iterator.next());}} }
面试题:
public class HashSetDemo {public static void main(String[] args) {HashSet set = new HashSet();Person p1 = new Person(1001,"AA");Person p2 = new Person(1002,"BB");set.add(p1);set.add(p2);System.out.println(set);p1.name = "CC";set.remove(p1);System.out.println(set);
//set.add(new Person(1001,"CC"));System.out.println(set); //hash值不一样,可以添加进去set.add(new Person(1001,"AA")); //跟最初p1的hash值一样System.out.println(set);}
}
Person
public class Person {double id;String name;public Person() {}public Person(double id, String name) {this.id = id;this.name = name;}//其中Person类中重写了hashCode()和equals()方法@Overridepublic boolean equals(Object o) {System.out.println("Person equals...");if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return Double.compare(id, person.id) == 0 && Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(id, name);}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +'}';}
}
Map接口
Map实现类之一:HashMap
HashMap的存储结构
HashMap源码中的重要常量
Map实现类之二:LinkedHashMap
Map实现类之三:TreeMap
Map实现类之四:Hashtable
Map实现类之五:Properties
总结:
1.Map及其实现类对比 java.util.Map:存储一对一对的数据(key-value键值对,(x1,y1)、(x2,y2) --> y=f(x),类似于高中的函数)|---- HashMap(主要实现类):线程不安全的,效率高;可以添加null的key和value值;底层使用数组+单向链表+红黑树结构存储(jdk8)|---- LinkedHashMap:是HashMap的子类;在HashMap使用的数据结构的基础上,增加了一对双向链表,用于记录添加的元素的先后顺序,进而我们在遍历元素时,就可以按照添加的顺序显示。开发中,对于频繁的遍历操作,建议使用此类。|---- TreeMap:底层使用红黑树存储;可以按照添加的key-value中的key元素的指定的属性的大小顺序进行遍历。需要考虑使用①自然排序 ②定制排序。|---- Hashtable:古老实现类,线程安全的,效率低;不可以添加null的key或value值;底层使用数组+单向链表结构存储(jdk8)|---- Properties:其key和value都是String类型。常用来处理属性文件。[面试题]:区别HashMap和Hashtable、区别HashMap和LinkedHashMap、HashMap的底层实现(① new HashMap() ② put(key,value))2. HashMap中元素的特点 > HashMap中的所有的key彼此之间是不可重复的、无序的。所有的key就构成一个Set集合。--->key所在的类要重写hashCode()和equals() > HashMap中的所有的value彼此之间是可重复的、无序的。所有的value就构成一个Collection集合。--->value所在的类要重写equals() > HashMap中的一个key-value,就构成了-个entry。 > HashMap中的所有的entry彼此之间是不可重复的、无序的。所有的entry就构成了一个Set集合。 3.Map中的常用方法 - 添加、修改操作:- Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中- void putAll(Map m):将m中的所有key-value对存放到当前map中 - 删除操作:- Object remove(Object key):移除指定key的key-value对,并返回value- void clear():清空当前map中的所有数据 - 元素查询的操作:- Object get(Object key):获取指定key对应的value- boolean containsKey(Object key):是否包含指定的key- boolean containsValue(Object value):是否包含指定的value- int size():返回map中key-value对的个数- boolean isEmpty():判断当前map是否为空- boolean equals(Object obj):判断当前map和参数对象obj是否相等 - 元视图操作的方法:- Set keySet():返回所有key构成的Set集合- Collection valves():返回所有value构成的Collection集合- Set entrySet():返回所有key-value对构成的Set集合 小结:增put(Object key,Object value)putALL(Map m)删Object remove(Object key)改:put(object key,Object value)putALL(Map m)查:Object get(object key)长度:size()遍历:遍历key集:Set keySet()遍历value集:Collection values()遍历entry集:Set entrySet() 4.TreeMap的使用 > 底层使用红黑树存储; > 可以按照添加的key-value中的key元素的指定的属性的大小顺序进行遍历 > 需要考虑使用①自然排序 ②定制排序。 > 要求:向TreeMap中添加的key必须是同一个类型的对象。 5.Hashtable与Properties的使用 Properties:是Hashtable的子类,其key和value都是String类型的,常用来处理属性文件。
相关代码:
MapTest
public class MapTest {/*** 测试Map中的实现类*/@Testpublic void test1(){Map map = new HashMap();map.put(null,null);System.out.println(map);}@Testpublic void test2(){Map map = new Hashtable();
// map.put(null,123); //NullPointerException报异常
// map.put("AA",null); //NullPointerException报异常System.out.println(map);}@Testpublic void test3(){LinkedHashMap map = new LinkedHashMap();map.put("Tom",23);map.put("CC",new Date());map.put(34,"AA");System.out.println(map);}/*** 测试Map中的常用方法* 增* put(Object key,Object value)* putALL(Map m)* 删* Object remove(Object key)* 改:* put(object key,Object value)* putALL(Map m)* 查:* Object get(object key)* 长度:* size()* 遍历:* 遍历key集:Set keySet()* 遍历value集:Collection values()* 遍历entry集:Set entrySet()*/@Testpublic void test4(){HashMap map = new HashMap();//添加:put(Object key,Object value)map.put("AA",56);map.put(67,"Tom");map.put("BB",78);map.put(new Person("Jerry",12),56);/*** {AA=56, BB=78, 67=Tom, Person{name='Jerry', age=12}=56}* 4*/System.out.println(map);System.out.println(map.size());//Object remove(Object key)Object value = map.remove("AA");System.out.println(value);System.out.println(map);//修改:put(object key,Object value)Object oldValue = map.put("BB", 99);System.out.println(oldValue); //78System.out.println(map);//Object get(object key)Object value1 = map.get(67);System.out.println(value1); //Tom}//map的遍历操作@Testpublic void test5(){HashMap map = new HashMap();map.put("AA",56);map.put(67,"Tom");map.put("BB",78);map.put(new Person("Jerry",12),56);// 遍历key集:Set keySet()Set keySet = map.keySet();//使用迭代器Iterator iterator = keySet.iterator();while(iterator.hasNext()){Object key = iterator.next();System.out.println(key);}//遍历value集:Collection values()//方式1:
// Collection values = map.values();
// //使用增强for
// for(Object obj : values){
// System.out.println(obj);
// }//方式2:Set keySet1 = map.keySet();for(Object key : keySet1){Object value = map.get(key);System.out.println(value);}}@Testpublic void test6(){HashMap map = new HashMap();map.put("AA",56);map.put(67,"Tom");map.put("BB",78);map.put(new Person("Jerry",12),56);//方式1:遍历entry集:Set entrySet()Set entrySet = map.entrySet();Iterator iterator = entrySet.iterator();while(iterator.hasNext()){//方式1:System.out.println(iterator.next());//方式2:
// Map.Entry entry = (Map.Entry) iterator.next();
// System.out.println(entry.getKey() + " ---> " + entry.getValue());}//方式2:遍历entry集:keySet()、get(key)Set keySet = map.keySet();for(Object key : keySet){System.out.println(key + " ---> " +map.get(key));}}
}
person类
public class Person {String name;int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {System.out.println("Person equals()...");if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age && Objects.equals(name, person.name);}
}
TreeMapTest
public class TreeMapTest {/*** 自然排序*/@Testpublic void test1(){TreeMap map = new TreeMap();map.put("CC",89);map.put("BB",78);map.put("JJ",new Date());map.put("MM",78);
// map.put(67,78); //报错ClassCastException,因为key的类型(Integer)与之前的key的类型(String)不一致Set entrySet = map.entrySet();for(Object entry : entrySet){System.out.println(entry);}}@Testpublic void test2(){TreeMap map = new TreeMap();User u1 = new User("Tom",23);User u2 = new User("Jerry",43);User u3 = new User("Rose",13);User u4 = new User("Jack",23);User u5 = new User("Tony",33);map.put(u1,78);map.put(u2,76);map.put(u3,88);map.put(u4,45);map.put(u5,99);Set entrySet = map.entrySet();for(Object entry : entrySet){System.out.println(entry);}
// System.out.println(map.containsKey(new User("Maria", 33))); //true}/*** 定制排序*/@Testpublic void test3(){Comparator comparator = new Comparator(){public int compare(Object o1, Object o2) {if(o1 instanceof User && o2 instanceof User){User u1 = (User)o1;User u2 = (User)o2;int value = u1.getName().compareTo(u2.getName());if(value != 0){return value;}return u1.getAge() - u2.getAge();}throw new RuntimeException("类型不匹配");}};TreeMap map = new TreeMap(comparator);User u1 = new User("Tom",23);User u2 = new User("Jerry",43);User u3 = new User("Rose",13);User u4 = new User("Jack",23);User u5 = new User("Tony",33);map.put(u1,78);map.put(u2,76);map.put(u3,88);map.put(u4,45);map.put(u5,99);Set entrySet = map.entrySet();for(Object entry : entrySet){System.out.println(entry);}}
}
PropertiesTest
public class PropertiesTest {@Testpublic void test1() throws IOException { //注意:因为涉及到流的操作,为了确保流能关闭,建议使用try-catch-finally//方式1:数据和代码耦合度高,如果修改的话,需要重写的编译代码、打包发布,繁琐//数据
// String name = "Tom";
// String password = "abc123";//代码:用于操作name,password//...//方式2:将数据封装到具体的配置文件中,在程序中读取配置文件中的信息,实现了//数据和代码的解耦,由于我们没有修改代码,就省去了重新编译和打包的过程File file = new File("info.properties"); //注意,要提前创建好
// System.out.println(file.getAbsolutePath());FileInputStream fis = new FileInputStream(file);Properties pros = new Properties();pros.load(fis); //加载流中的文件中的数据//读取数据String name = pros.getProperty("name");String pwd = pros.getProperty("password");System.out.println(name + ":" + pwd); //Tom:abc123fis.close();}// public static void main(String[] args) {
// File file = new File("info.properties");
// System.out.println(file.getAbsolutePath());
// }
}
User
public class User implements Comparable{private String name;private int age;public User() {}public User(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}// @Override
// public boolean equals(Object o) {
// System.out.println("User equals()...");
// if (o == null || getClass() != o.getClass()) return false;
// User user = (User) o;
// return age == user.age && Objects.equals(name, user.name);
// }
//
// @Override
// public int hashCode() {
// return Objects.hash(name, age);
// }/*** 按照年龄的从小到大排序* @param o the object to be compared.* @return*/@Overridepublic int compareTo(@NotNull Object o) {if(this == o) {return 0;}if(o instanceof User){User u = (User)o;return this.age - u.age;}throw new RuntimeException("类型不匹配");}/*** 比如:先比较年龄从小到大排列,如果年龄相等,则继续比较姓名,从小到大*/
// @Override
// public int compareTo(@NotNull Object o) {
// if(this == o) {
// return 0;
// }
// if(o instanceof User){
// User u = (User)o;
// int value = this.age - u.age;
// if(value != 0){
// return value;
// }
// return -this.name.compareTo(u.name);
// }
// throw new RuntimeException("类型不匹配");
// }
}
练习:
添加你喜欢的歌手以及你喜欢他唱过的歌曲,并遍历public class StringTest {public static void main(String[] args) {HashMap singers = new HashMap();String singer1 = "周杰伦";ArrayList songs1 = new ArrayList();songs1.add("夜曲");songs1.add("晴天");songs1.add("七里香");songs1.add("发如雪");songs1.add("屋顶");songs1.add("青花瓷");singers.put(singer1,songs1);//在添加1个歌手和其歌曲String singer2 = "林俊杰";ArrayList songs2 = new ArrayList();songs2.add("江南");songs2.add("曹操");songs2.add("小酒窝");songs2.add("可惜没如果");singers.put(singer2, songs2);Set entrySet = singers.entrySet();Iterator iterator = entrySet.iterator();while(iterator.hasNext()){Map.Entry entry = (Map.Entry)iterator.next();System.out.println("歌手:" + entry.getKey());System.out.println("歌曲有:" + entry.getValue());}} }
练习2
案例:二级联动 将省份和城市的名称保存在集合中,当用户选择省份以后,二级联动,显示对应省份的地级市供用户选择。 效果演示见课件。 如果输入的城市不正确,需要重新输入。提示:如果输入的省份不正确,需要重新输入。 已有代码: class CityMap{public static Map model=new HashMap();static {model.put("北京",new string[]{"北京"});model.put("辽宁",new string[]{"沈阳","盘锦","铁岭","丹东","大连","锦州""营口"});model.put("吉林",new String[]{"长春",“延边”,"吉林",“白山","白城”,"四平","松原"});model.put("河北",new string[]{"承德","沧州","邯郸","邢台""唐山","保定","石家庄"});model.put("河南", new String[]{"郑州",“许昌",“开封","洛阳",“商丘”,“南阳",“新乡"});model.put("山东", new string[]{"济南","青岛",“日照","临沂","泰安","聊城","德州"});} }public class CityMapTest {public static void main(String[] args) {//1.获取Map,并遍历map中的所有的keyMap map = CityMap.model;Set provinces = map.keySet();for(Object province : provinces){System.out.println(province + "\t\t");}//2.根据提示,从键盘获取省份,判断此省份是否存在,如果存在遍历其value中的各个城市//如果不存在,提示用户重新输入Scanner scan = new Scanner(System.in);String[] cities;while(true){System.out.println("\n请选择你所在的省份:");String province = scan.next();//获取省份对应的各个城市构成的String[]cities = (String[])map.get(province);if(cities == null && cities.length == 0){System.out.println("你输入的省份有误,请重新输入");}else {break; //意味着用户输入的省份是存在的,则跳出当前循环}}for(int i = 0; i < cities.length;i++){System.out.println(cities[i] + "\t\t");}System.out.println();//3.根据提示,从键盘获取城市,遍历各个城市构成的String[],判断输入的城市是否存在于此数组中//如果存在,信息登记完毕,如果不存在,提示用户重新输入l:while(true){System.out.println("\n请选择你所在的城市:");String city = scan.next();//方式1: // for(int i = 0;i<cities.length;i++){ // if(city.equals(cities[i])){ // System.out.println("信息登记完毕"); // break l; // } // } // System.out.println("输入的城市有误,请重新输入");//方式2:if(containsCity(cities,city)){System.out.println("信息登记完毕");break;}System.out.println("输入的城市有误,请重新输入");}scan.close();}//第2种方式处理城市是否存在public static boolean containsCity(String[] cities,String city){for(int i = 0;i<cities.length;i++){if(city.equals(cities[i])){System.out.println("信息登记完毕");return true;}}return false;} } class CityMap{public static Map model = new HashMap();static {model.put("北京",new String[]{"北京"});model.put("辽宁",new String[]{"沈阳","盘锦","铁岭","丹东","大连","锦州","营口"});model.put("吉林",new String[]{"长春","延边","吉林","白山","白城","四平","松原"});model.put("河北",new String[]{"承德","沧州","邯郸","邢台","唐山","保定","石家庄"});model.put("河南", new String[]{"郑州","许昌","开封","洛阳","商丘","南阳","新乡"});model.put("山东", new String[]{"济南","青岛","日照","临沂","泰安","聊城","德州"});} }
Collections工具类
总结:
1.Collections概述 Collections 是一个操作 Set、List 和 Map 等集合的工具类 2. 常用方法 Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可 变、对集合对象实现同步控制等方法(均为static方法): 排序操作: reverse(List):反转 List 中元素的顺序 shuffle(List):对 List 集合元素进行随机排序 sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序 sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序 swap(List,int, int):将指定 list 集合中的i处元素和j处元素进行交换 查找 Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素 Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素。 object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素 Object min(Collection,comparator):根据 Comparator 指定的顺序,返回给定集合中的最小元素 int binarySearch(list list,T key)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且必须是可比较大小的,即支持自然排序的。而且集合也事先必须是有序的,否则结果不确定。 int binarySearch(List list,T key,Comparator c)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子 类对象,而且集合也事先必须是按照c比较器规则进行排序过的,否则结果不确定 int frequency(Collection c,Object o):返回指定集合中指定元素的出现次数 复制、替换 void copy(List dest,List src):将src中的内容复制到dest中 boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值 提供了多个unmodifiableXxx(方法,该方法返回指定 Xxx的不可修改的视图。 添加 boolean addAll(Collection c,T....elements)将所有指定元素添加到指定 collection 中。 同步 Collections 类中提供了多个synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合, 从而可以解决多线程并发访问集合时的线程安全问题:3,面试题:区分Collection和Collections Collection:集合框架中的用于存储一个一个元素的接口,又分为List和Set等子接口。 Collections:用于操作集合框架的一个工具类。此时的集合框架包括:Set、List、Map
代码:
public class CollectionsTest {/*** reverse(List):反转 List 中元素的顺序* shuffle(List):对 List 集合元素进行随机排序* sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序* sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序* swap(List,int, int):将指定 list 集合中的i处元素和j处元素进行交换*/@Testpublic void test1(){List list = Arrays.asList(45, 43, 65, 6, 43, 2, 32, 45, 56, 34, 23);System.out.println(list);//reverse(List):反转 List 中元素的顺序
// Collections.reverse(list);//shuffle(List):对 List 集合元素进行随机排序
// Collections.shuffle(list);//sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
// Collections.sort(list);//sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序Collections.sort(list, new Comparator(){@Overridepublic int compare(Object o1, Object o2) {if(o1 instanceof Integer && o2 instanceof Integer){Integer i1 = (Integer)o1;Integer i2 = (Integer)o2;
// return i1 - i2;return -(i1.intValue() - i2.intValue()); //拆箱}throw new RuntimeException("类型不匹配");}});System.out.println(list);}/*** 查找* Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素* Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素。* object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素* Object min(Collection,comparator):根据 Comparator 指定的顺序,返回给定集合中的最小元素* int binarySearch(list list,T key)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子类对象,而且* 必须是可比较大小的,即支持自然排序的。而且集合也事先必须是有序的,否则结果不确定。* int binarySearch(List list,T key,Comparator c)在List集合中查找某个元素的下标,但是List的元素必须是T或T的子* 类对象,而且集合也事先必须是按照c比较器规则进行排序过的,否则结果不确定* int frequency(Collection c,Object o):返回指定集合中指定元素的出现次数*/@Testpublic void test2(){List list = Arrays.asList(45, 43, 65, 6, 43, 2, 32, 45, 56, 34, 23);System.out.println(list);Object max = Collections.max(list);Object max1 = Collections.max(list,new Comparator(){@Overridepublic int compare(Object o1, Object o2) {if(o1 instanceof Integer && o2 instanceof Integer){Integer i1 = (Integer)o1;Integer i2 = (Integer)o2;
// return i1 - i2;return i1.intValue() - i2.intValue(); //拆箱}throw new RuntimeException("类型不匹配");}});System.out.println(max+ "\t" +max1); //65int count = Collections.frequency(list, 45);System.out.println("45出现了" + count + "次");}@Testpublic void test3(){List src = Arrays.asList(45, 43, 65, 6, 43, 2, 32, 45, 56, 34, 23);System.out.println(src);//void copy(List dest,List src):将src中的内容复制到dest中//错误的写法:
// List dest = new ArrayList();
// System.out.println(dest.size()); //0//正确的写法:List dest = Arrays.asList(new Object[src.size()]);System.out.println(dest.size()); //11Collections.copy(dest,src);System.out.println(dest);}/*** 提供了多个unmodifiableXxx(方法,该方法返回指定 Xxx的不可修改的视图。*/@Testpublic void test4(){List list1 = new ArrayList();//list1可以写入数据list1.add(34);list1.add(12);list1.add(45);List list2 = Collections.unmodifiableList(list1);//此时的list2只能读,不能写list2.add("AA"); //不能写System.out.println(list2.get(0));}@Testpublic void test5(){//Collections 类中提供了多个synchronizedXxx() 方法List list1 = new ArrayList();//返回的list2就是线程安全的List list2 = Collections.synchronizedList(list1);list2.add(123);HashMap map1 = new HashMap();//返回的map2就是线程安全的Map map2 = Collections.synchronizedMap(map1);}
}
练习题(斗地主):
模拟斗地主洗牌和发牌,牌没有排序 效果如图。 提示:不要忘了大王、小王 String[] num = {"A","2","3","4","5","6","7","8","9","J", "Q","K"}; String[] color = {"方片◆","梅花♣","红桃♥","黑桃♠"}; ArrayList poker = new ArrayList();public class PokerTest {public static void main(String[] args) {//1.组成一副扑克牌String[] num = {"A","2","3","4","5","6","7","8","9","J", "Q","K"};String[] color = {"方片◆","梅花♣","红桃♥","黑桃♠"};ArrayList poker = new ArrayList();for(int i = 0; i < color.length; i++){for(int j = 0; j < num.length; j++){poker.add(color[i] + "" + num[j]);}}//添加大小王poker.add("小王");poker.add("大王");//2.洗牌Collections.shuffle(poker);//3.发牌//3.1 创建3个角色和1个底牌对应的4个ArrayListArrayList tom = new ArrayList();ArrayList jerry = new ArrayList();ArrayList me = new ArrayList();ArrayList lastCards = new ArrayList();for(int i = 0; i < poker.size(); i++){if(i>=poker.size() - 3){lastCards.add(poker.get(i));}else if(i%3 == 0){tom.add(poker.get(i));}else if(i%3 ==1){jerry.add(poker.get(i));}else if(i%3 == 2){me.add(poker.get(i));}}//3.2遍历显示4个ArrayListSystem.out.println("Tom:");System.out.println(tom);System.out.println("Jerry:");System.out.println(jerry);System.out.println("Me:");System.out.println(me);System.out.println("底牌:");System.out.println(lastCards);} }
相关文章:
java学习笔记10——集合框架
枚举类的使用 Collection接口继承树 Map接口继承树 Collection 接口方法 总结: 集合框架概述 1.内存层面需要针对于多个数据进行存储。此时,可以考虑的容器有:数组、集合类2.数组存储多个数据方面的特点:> 数组一旦初始化,其长度就是确定的…...
埃文科技企业AI大模型一体机——昇腾体系+DeepSeek+RAG一站式解决方案
面对企业级市场海量数据资产与复杂业务场景深度耦合的刚需,埃文科技重磅推出基于华为昇腾算力DeepSeek大模型的企业一体机产品,提供DeepSeek多版本大模型一体机选择,为企业提供本地昇腾算力DeepSeek大模型RAG知识库的一体化解决方案ÿ…...
蓝桥杯---BFS解决FloofFill算法1---图像渲染
文章目录 1.算法简介2.题目概述3.算法原理4.代码分析 1.算法简介 这个算法是关于我们的floodfill的相关的问题,这个算法其实从名字就可以看出来:洪水灌溉,其实这个算法的过程就和他的名字非常相似,下面的这个图就生动的展示了这个…...
个人博客网站从搭建到上线教程
步骤1:设计个人网站 设计个人博客网站的风格样式,可以在各个模板网站上多浏览浏览,以便有更多设计网站风格样式的经验。 设计个人博客网站的内容,你希望你的网站包含哪些内容如你的个人基本信息介绍、你想分享的项目、你想分享的技术文档等等。 步骤2:选择开发技术栈 因…...
【FreeRTOS】裸机开发与操作系统区别
🔎【博主简介】🔎 🏅CSDN博客专家 🏅2021年博客之星物联网与嵌入式开发TOP5 🏅2022年博客之星物联网与嵌入式开发TOP4 🏅2021年2022年C站百大博主 🏅华为云开发…...
力扣每日一题:2712——使所有字符相等的最小成本
使所有字符相等的最小成本 题目示例示例1示例2 题解这些话乍一看可能看不懂,但是多读两遍就明白了。很神奇的解法,像魔术一样。 题目 给你一个下标从 0 开始、长度为 n 的二进制字符串 s ,你可以对其执行两种操作: 选中一个下标…...
Java EE(17)——网络原理——IP数据报结构IP协议解析(简述)
一.IP数据报结构 (1)版本:指明协议的版本,IPv4就是4,IPv6就是6 (2)首部长度:单位是4字节,表示IP报头的长度范围是20~60字节 (3)8位区分服务:实际上只有4位TOS有效,分别是最小延时,最…...
Pycharm运行时报“Empty suite”,可能是忽略了这个问题
问题:使用Pycharm运行testcases目录下的.py文件,报“Empty suite”,没有找到测试项。 排查过python解释器、pytest框架安装等等,依然报这个错,依然没找到,最后终端运行: pytest test_demo.py&a…...
Linux快速安装docker和docker-componse步骤
在 CentOS 7 上安装 Docker 和 Docker Compose 的步骤如下: 1. 安装 Docker 1.1. 更新系统 首先,确保你的系统是最新版本: sudo yum update -y1.2. 安装必要的包 安装 yum-utils,这是管理 YUM 源的工具: sudo yu…...
OP2177运算放大器:高性能模拟信号处理的关键元件
在现代电子系统中,模拟信号处理至关重要,运算放大器作为模拟电路的核心部件,其性能优劣直接影响系统的整体表现。OP2177 是一款具有卓越性能的运算放大器,在众多领域有着广泛应用。以下将结合相关资料,对 OP2177 进行全…...
paddle ocr
paddle ocr paddle ocr笔记准备工作referenceto onnx文本检测文本检测文字识别 paddle ocr笔记 准备工作 下载字典ppocr_keys_v1.txt,下标从1开始模型转换 reference paddlepaddle to onnx 下载模型,或者直接使用python跑一下并且把本地模型拿过来…...
通过动态获取项目的上下文路径来确保请求的 URL 兼容两种启动方式(IDEA 启动和 Tomcat 部署)下都能正确解析
背景 因为在不同的启动环境下,获取上下文路径的方式需要有所调整。在 IDEA 中运行时,路径是基于当前页面的 URL(如 index.html),而在 Tomcat 部署时,它是基于项目上下文路径(如 ssm-project&am…...
Spring Boot 整合 ElasticJob 分布式任务调度教程
精心整理了最新的面试资料和简历模板,有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 Spring Boot 整合 ElasticJob 分布式任务调度教程 一、ElasticJob 简介 ElasticJob 是当当网开源的分布式任务调度解决方案,支持: …...
Django项目之订单管理part6(message组件和组合搜索组件)
一.前言 我们前面讲的差不多了,接着上节课讲,今天要来做一个撤单要求,我们可以用ajax请求,但是我这里介绍最后一个知识点,message组件,但是我会把两种方式都讲出来的,讲完这个就开始讲我们最重…...
[MySql] 多表关系, 多表查询
一. 多表关系 1.1 一对多 例如: 员工 - 部门表 (一个部门可以有多个员工) 并且在多的一方增加一个字段关联一的一方的主键. 外键约束: 物理外键 (使用 foreign key 定义外键关联另一张表的主键) 缺点: 影响增删改效率; 仅用于单节点, 不适用与集群; 易引发死锁, 性能低; …...
Open GL ES ->GLSurfaceView在正交投影下的图片旋转、缩放、位移
XML文件 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:o…...
一文详解QT环境搭建:Windows使用CLion配置QT开发环境
在当今的软件开发领域,跨平台应用的需求日益增长,Qt作为一款流行的C图形用户界面库,因其强大的功能和易用性而备受开发者青睐。与此同时,CLion作为一款专为C/C打造的强大IDE,提供了丰富的特性和高效的编码体验。本文将…...
MSTP和链路聚合
MSTP 802.1S --- MSTP --- 多生成树协议 --- 就是在RSTP基础上,再针对链路利用率低问题进行优化,可以和RSTP以及STP向下兼容。 实例 --- Instance --- 可以理解为一个V LAN或者多个VALN的集合。一个交换网络可以针对一个实例创建一棵树,起到…...
每天学一个 Linux 命令(8):ls
大家好,欢迎来到《每天掌握一个Linux命令》系列。在这个系列中,我们将逐步学习并熟练掌握Linux命令,今天,我们要学习的命令是ls。 01 什么是ls命令 在Linux系统中,ls命令是“list”的缩写,其英文全称为“list directory contents”,即“列出目录内容”。该命令非常实用…...
交换机、路由器、VLAN、单臂路由、三层交换、STP
华为模拟安装 1.依次安装wincap 2.wireshark 3.virtual box 4.ensp 一、设置 1.virtual box设置 2.计算机防火墙允许以上程序 3.eNSP设置 路由器:AR2240 交换机:S5700、CE12800 防火墙USG6000V 交换机 一、交换机工作原理 1、回顾 二层交换机…...
算法 | 2024最新算法:斑翠鸟优化算法原理,公式,应用,算法改进研究综述,matlab代码
基于斑翠鸟优化算法的原理、应用及改进研究综述 一、算法原理 斑翠鸟优化算法(Pied Kingfisher Optimizer, PKO)是2024年由Bouaouda等人提出的一种新型仿生智能优化算法,其灵感来源于斑翠鸟的捕食行为与共生关系。算法通过模拟斑翠鸟的栖息悬停、潜水捕鱼及与其他生物的共生…...
六十天Linux从0到项目搭建(第二十二天)(pipe、管道四种场景)
1 关于 pipe 系统调用的解析 int pipe(int pipefd[2]) 是 Unix/Linux 系统中用于创建匿名管道的系统调用。以下是关于管道特点的详细解释: 输出型参数 pipefd[2] 是输出型参数,调用成功后: pipefd[0] 存放管道的读取端文件描述符 pipefd[1…...
数据安全与网络安全——问答复习
目录 1、请简要分析勒索软件攻击的原理,并给出技术防护⽅案。 勒索软件攻击原理: 技术防护⽅案 2、举例数据安全问题 数据泄露 数据篡改 数据丢失 3、如何应对数据安全问题 技术层⾯ 管理层⾯ 4、软件漏洞 产⽣原因: 缓冲区溢出漏洞: 注⼊漏…...
ESP-01模块连接手机热点问题及解决方法
在使用ESP-01模块连接手机热点时,可能会遇到一些问题。本文将详细介绍如何解决这些问题,并分享最终通过将WiFi切换到2.4GHz成功解决问题的经验。 一、问题描述 在尝试使用ESP-01模块连接手机热点时,遇到了连接失败的问题。以下是操作过程中…...
go中锁的入门到进阶使用
Go 并发编程:从入门到精通的锁机制 引言:为什么需要锁? Go 语言以其天生支持并发的特性深受开发者喜爱,但并发带来的问题也不容小觑,比如数据竞争、并发安全等。如果多个 Goroutine 访问同一个变量,没有做…...
JS判断对象是否为空的方法
在 JavaScript 中,判断一个对象是否为空对象(即没有自身可枚举属性),可以通过以下方法实现: 方法 1:使用 Object.keys() javascript function isEmptyObject(obj) {// 确保是普通对象(排除 n…...
idea导入tomcat的jar
概述 对于老项目,未使用 Maven/Gradle 管理依赖的,在需要编译 Servlet/JSP 代码时,需要手动添加 Tomcat JAR 依赖(如 servlet-api.jar)方能进行编绎。 步骤: 1、找到 Tomcat 的 JAR 文件 进入 Tomcat 安…...
Linux 下安装和使用 Jupyter Notebook
Jupyter Notebook / Lab 是 Python 开发和数据分析中不可或缺的工具。为了避免环境污染,推荐使用虚拟环境方式安装并启动它。本教程将教你如何: 安装 Python、pip、venv使用虚拟环境安装 Jupyter汉化安装实用插件设置登录密码启动并远程访问编写一个一键…...
【Ubuntu常用命令】
1.将本地服务器文件或文件夹传输到远程服务器 文件 scp /data/a.txt administrator10.60.51.20:/home/administrator/ 文件夹 scp -r /data/ administrator10.60.51.20:/home/administrator/ 2.从远程服务器传输文件到本地服务器 scp administrator10.60.51.20:/data/a.txt /h…...
UR机械臂sim2real推荐包
推荐一个和ur机械臂配套的interface: ur_rtde Universal Robots RTDE C Interface — ur_rtde 1.6.0 documentation 也欢迎大家提供新想法和bug...
HTTP协议深度解析详解
HTTP协议深度解析详解 一、HTTP协议基础架构 1.1 请求响应模型 #mermaid-svg-pAGwQipduFJRm11I {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-pAGwQipduFJRm11I .error-icon{fill:#552222;}#mermaid-svg-pAGwQipd…...
算法学习第十七天:LRU缓存与布隆过滤器
LRU缓存与布隆过滤器 目录 LRU缓存 基本概念实现原理C代码实现 布隆过滤器 基本概念实现原理C代码实现 LRU缓存 基本概念 LRU(Least Recently Used):最近最少使用策略,当缓存空间不足时,淘汰最久未被访问的数据。…...
html中img标签直接使用border-radius时会图片进行了遮挡
前言 该问题是我写完项目之后,UI走查发现的问题,虽然我也发现了问题,但是改起来,不好改,就耽搁了。后面UI还是要求要改。一直找不到解决方案,歪打正着通过MDN官网偶然看到的clip-path属性。 需求 一个图…...
【Keepalived】Keepalived-2.3.3明确结束对CentOS 7的支持
2025年3月30日,官方发布了Keepalived的最新版,版本号:2.3.3 而2024年11月3日发布的2.3.2版本,在CentOS 7.9上编译的时候,就出现了报错,但是在Alma Linux 8.10上,则可以成功编译安装,…...
Docker学习--容器生命周期管理相关命令--docker pause/unpause 命令
docker pause 命令的作用: 用于暂停一个或多个容器中的所有进程。 语法: docker pause CONTAINER [CONTAINER…](要操作的容器的名称,可以同时操作多个)。 实例: ①暂停一个容器及其所有进程:…...
【Zabbix技术系列文章】第④篇——Zabbix 数据可视化
在当今数字化运维时代,面对海量的监控数据,如何从中快速获取有价值的信息至关重要。Zabbix 的数据可视化功能为我们提供了直观、高效的解决方案,它能将复杂的监控数据转化为清晰易懂的图表和仪表盘,助力运维人员迅速发现问题、分析…...
R CSV 文件处理指南
R CSV 文件处理指南 引言 CSV(逗号分隔值)文件是一种常见的文件格式,它以纯文本形式存储表格数据。在R语言中,CSV文件处理是非常基础且重要的技能。本文将详细介绍如何在R中读取、处理和导出CSV文件,并探讨一些高级技…...
在Git仓库的Readme上增加目录页
一般在编写Readme时想要增加像文章那样的目录,方便快速跳转,但是Markdown语法并没有提供这样的方法,但是可以通过超链接结合锚点的方式来实现,如下图是我之前一个项目里写的Readme: 例如有下面几个Readme内容ÿ…...
[特殊字符]《多商户家政系统技术解析:SpringBoot+MyBatisPlus+UniApp高效实战指南》
🛠️ 引言:多商户家政系统的技术挑战与价值 在数字化时代,家政行业逐渐向线上迁移,从传统的线下预约转向平台化管理。多商户家政系统具备复杂的角色体系,包括: 🛎️ 商户端:管理订单…...
请求Header(Request Headers)详解
请求Header(Request Headers)详解 HTTP请求Header是HTTP请求消息的重要组成部分,用于在客户端和服务器之间传递附加信息。这些信息帮助服务器理解客户端的环境、偏好和请求的具体内容,从而能够返回更合适的响应。以下是对请求Hea…...
深度求索:开源革命下的AI普惠之路
引言:AI领域的破局者 2025年,全球AI领域因一家中国公司的崛起而震动。杭州深度求索(DeepSeek)推出的V3大模型以6710亿参数、14.8万亿token训练数据量,在数学竞赛、代码生成等专业领域超越多数国际竞品,其每…...
XSS 攻击(详细)
目录 引言 一、XSS 攻击简介 二、XSS 攻击类型 1.反射型 XSS 2.存储型 XSS 3.基于 DOM 的 XSS 4.Self - XSS 三、XSS 攻击技巧 1.基本变形 2.事件处理程序 3.JS 伪协议 4.编码绕过 5.绕过长度限制 6.使用标签 四、XSS 攻击工具与平台 1.XSS 攻击平台 2.BEEF 五…...
使用Redis实现轻量级消息队列
使用消息中间件如RabbitMQ或kafka虽然好,但也给服务器带来很大的内存开销,当系统的业务量,并发量不高时,考虑到服务器和维护成本,可考虑使用Redis实现一个轻量级的消息队列,实现事件监听的效果。下面介绍下…...
13届省赛python A组:10.数的拆分
题目1 数的拆分 给定 T 个正整数 ai,分别问每个 ai 能否表示为 x 1 y 1 ⋅ x 2 y 2 x1^{y1}⋅x2^{y2} x1y1⋅x2y2 的形式,其中 x1,x2 为正整数,y1,y2 为大于等于 2 的正整数。 输入格式 输入第一行包含一个整数 T 表示询问次数。 接下来…...
【Android Studio】下载安装过程(详细)
目录 一、前期准备 JDK下载安装 二、下载安装 下载 安装 启动 一、前期准备 JDK下载安装 详细的安装过程请移步我的另一篇博客jdk17详细安装步骤_jdk17安装教程详细-CSDN博客 cmd打开命令行,输入java -version验证,可以看到此处我安装的是java23。…...
【RAGFlow】ubuntu22部署ragflow(v0.17.2)
按照官方手册部署: https://ragflow.io/docs/v0.17.2/ 部署环境: CPU: 4核memory: 16gGPU: T4(vGPU)Disk: 20g 1. 配置国内docker-ce源 https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/ 用清华源,要不然下载速度感人 …...
Easysearch 如何短暂维护 Data 节点
之前介绍过如何移除 Data 节点,那么如果只是短暂停止一个 Data 节点进行维护,之后再次加入集群,是否也需要按照移除节点的步骤进行操作呢?我们先梳理下核心原理。 核心原理 我们先看看节点离开集群之后集群是怎样处理的。当节点…...
【cocos creator 3.x】3Dui创建,模型遮挡ui效果
官方文档:https://docs.cocos.com/creator/3.8/manual/zh/ui-system/components/editor/ui-model.html 1、3Dui创建 创建label,默认会添加canvas根节点和2dCamera 将Camera删除,canvas上组建去除cc.Canvas,cc.widget࿰…...
UE5学习笔记 FPS游戏制作32 主菜单,暂停游戏,显示鼠标指针
文章目录 一主菜单搭建UI显示主菜单时,暂停游戏,显示鼠标绑定按钮 二 打开主菜单 一主菜单 搭建UI 添加一个MainUi的控件 添加一个返回游戏的按钮和一个退出游戏的按钮 修改一下样式,放中间 显示主菜单时,暂停游戏࿰…...
有哪些开源的视频生成模型
1. 阿里巴巴通义万相2.1(WanX 2.1) 技术架构:基于Diffusion Transformer(DiT)架构,结合自研的高效变分自编码器(VAE)和Flow Matching训练方案,支持时空上下文建模。参数…...