目录
Java集合概述
Set
HashSet
特点:
-
不保证元素的排列顺序
-
存储的元素不可重复
-
一个HashSet对象可以存储不同类型的元素
-
元素可以是null,表示空
-
不线程安全
-
HashSet用法
-
可以存储多种不同类型元素,有排序
-
由结果可知,不会存放重复元素,null重复是因为一个是空一个是字符串,可以存放空指针null,对象也不是按照添加顺序排序
-
- Set set2 = new HashSet();
-
- Set set4 = new HashSet();//使用HashSet
-
- set1.add(99);//添加元素
-
- System.out.println(set1);//打印集合
-
- set1.remove(1);//移除元素1
-
- System.out.println(set1.contains(“a”));//判断是否包含元素a
-
- set1.clear();//清空集合
-
- set.size()输出集合长度
Set set2 = new HashSet();
set2.add("a");
set2.add("b");
set2.add("c");
set2.add("d");
System.out.println(set2);
System.out.println(set2.size());//4
public static void main(String[] arghs){
Set set1 = new HashSet();//Set引用类型接收HashSet对象
set1.add(99);//添加元素
set1.add(3);
set1.add(1);
set1.add("bb");
set1.add(2);
set1.add(4);
set1.add("a");
set1.add("a");
set1.add(null);
set1.add("null");
System.out.println(set1);
set1.remove(1);//移除元素
System.out.println(set1);
System.out.println(set1.contains("a"));//判断是否包含元素a
set1.clear();//清空集合
System.out.println(set1);
}
使用迭代器Iterator遍历集合HashSet,for each迭代集合
- 使用Iterator接口遍历集合,使用foreach遍历
- 这两种都是只能遍历,不能更改内容
Iterator it = set2.iterator();
while(it.hasNext()){System.out.print(it.next()+" "); }
//Iterator
Set set2 = new HashSet();
set2.add("a");
set2.add("b");
set2.add("c");
set2.add("d");//set集合存的值是不重复
System.out.println(set2);
//使用迭代器遍历集合
Iterator it = set2.iterator();
while(it.hasNext()){
System.out.print(it.next()+" ");
}
System.out.println();
//for each迭代集合
for(Object obj : set2){//把set2的每一个值取出来,赋值给obj,直到循环set的所有值
System.out.print(obj+" ");
}
- HashSet指定类型存储
Set<Object> set5 = new HashSet<Object>();
- 指定String为集合的泛型,这个集合不能存String之外的数据类型,只能存String类
Set set3 = new HashSet();
Set<String> set4 = new HashSet<String>();//指定String为集合的泛型,这个集合不能存String之外的数据类型,只能存String类
String s1 = "7";
String s2 = "uyjsdas";
set4.add(s1);
set4.add(s2);
set4.add("");
set4.add(null);
set4.add("haha");
set4.add("中国");
// set4.add(8);
System.out.println(set4);
- 指定Object,只能存对象,但是基本数据类型也可以储存,因为每一种基本数据类型都是转化为对应的引用类型然后存储 (没有意义,集合本来就只能存引用对象)
//对象类型的HashSet
Set<Object>set5 = new HashSet<Object>();
set5.add(new Test());
set5.add(new A());
set5.add(7);
set5.add("iut");
System.out.println(set5);
hashcode()方法
TreeSet
特点:
- 存入元素时,自动排序存储
- 只能存一种数据类型,不指定泛型时,按照集合内存储的第一个元素的类型为标准
- 两种排序方法:1.自然排序 2.定制排序
- TreeSet用法
- TreeSet不能存储重复元素,自然排序从小到大,只能存储一种类型的元素
-
- Set set6 = new TreeSet();
-
- Set set8 = new TreeSet(new Person());//使用TreeSet
-
- set6.add(5);//添加元素
-
- System.out.println(set6);//打印集合
-
- set6.remove(5);//移除元素5
-
- System.out.println(set6.contains(5));//元素5是否存在在集合中
-
- set8.clear();//清空集合
//TreeSet
//TreeSet
Set<Integer> set6 = new TreeSet<Integer>();
set6.add(5);
set6.add(98);
set6.add(5);
set6.add(0);
System.out.println(set6);
set6.remove(5);
System.out.println(set6);
System.out.println(set6.contains(5));
注:TreeSet不指定类型的情况下,只能存一种类型的元素。但是HashSet可以存储各种不同基本数据类型的元素
不指定List的泛型时,按照已经存储的第一位元素类型为标准
- 存储过数据之后删除,也不会确定List的泛型,还是按照有存储的第一位元素的类型为这个List对象的泛型标准
// TreeSet不定义类型时,只能存一种数据类型,重复数据不存
Set set7 = new TreeSet();
set7.add(7);
set7.remove(7);
set7.add("fgr");
set7.remove("fgr");
// set7.add("oiu7");
// set7.add("i");
// set7.add("i");
set7.add(true);
System.out.println(set7);
使用迭代器Iterator遍历集合TreeSet,for each迭代集合
- for each只能输出不能更改
//使用迭代器Iterator遍历集合
Iterator<Integer> it2 = set6.iterator();
while(it2.hasNext()){
System.out.print(it2.next()+",");//0,78,98,897,
}
System.out.println();
//使用foreach遍历集合
for(Integer i :set6){
System.out.print(i+",");//0,78,98,897,
}
★定制排序
- 两种定制排序对比
- 其中compareTo方法可以直接使用在是不是Interger,Character,Double,Float,Long,Short,Byte这七种除过Boolean类型的,基本数据类型的包装类还有String(个人理解)
继承接口Comparable重写其方法 public int compareTo(E o)
- 也称自然排序(未重写的自然排序遵循的是字典排序)
- compareTo()方法(1.参数为基本数据类型返回-1,0,1+2.参数为String类返回的值小于0,0,大于0)
继承接口Comparator,重写其方法public int compare(E o1,E o2)
-
也称比较器(1.与自然排序的定制一样,在自定义类中重写比较器。new集合时参数提供"new E()" 2.如果是一个普通类,则在new集合时参数提供"new Comparetor < E > 对象,并在其中重写比较器",定制排序)
-
定义Person类的排序方式,定制Person类存入的自然排序,使按照年龄从小到大排序
-
Persdon实现
Comparator<Person>
抽象类,实现其中的抽象方法public int compare(Person o1, Person o2) ;
-
compare方法中定义
return 1
则认为o1 > o2
排序为o2,o1,return -1
则o1 < o2
,return 0
则o1 == o2
。且整体由小到大排序
-
定义Person类,定制比较方法
import java.util.Comparator;
public class Person implements Comparator<Person> {//把Person对象存到TreeSet中并且按照年龄排序
public Person(){
}
public Person(String name, int age){
this.name = name;
this.age = age;
}
String name;
int age;
/**
* @Description: 定义比较大小方式
* @Param: [o1, o2]
* @return: int
* @Author: xuexuezi
* @Date: 2022/9/8
*/
@Override
public int compare(Person o1, Person o2) {//年龄正序排列
//return 0;
if(o1.age > o2.age){
return 1;
}else if(o1.age < o2.age){
return -1;
}else{
return 0;
}
}
public void showInfo(){
System.out.println("姓名:"+this.name+"年龄:"+this.age);
}
}
- foreach遍历存Person的集合TreeSet
//Set<Person> set8 = new TreeSet<Person>();错误
Set<Person> set8 = new TreeSet<Person>(new Person());
set8.add(p1);
set8.add(p2);
set8.add(p3);
set8.add(p4);
System.out.println(set8);
//[com.qx.day10.Person@2db0f6b2, com.qx.day10.Person@3cd1f1c8, com.qx.day10.Person@3a4afd8d, com.qx.day10.Person@1996cd68]
for(Person p: set8){
System.out.println(p.name+" "+p.age);
}
- 年龄倒序排序,则使o1.age<o2.age时return 1,此时依旧认为o1>o2,将o1排在o2之后
-
- 改写Person类中的compare方法
@Override
public int compare(Person o1, Person o2){//年龄倒序排列
if(o1.age > o2.age){
return -1;//认为o1<o2,o2排在后
}else if(o1.age < o2.age){
return 1;
}else{
return 0;
}
}
注:
- 发现定制排序中一个缺陷,无法存放年龄相同的人,认定o1和o2相等return 0 的情况下,TreeSet中只存一个。
- 理解为通过年龄排序,年龄即为key值,不能重复存放。但该对象的姓名之类的属性都可以随意相同
Person p1 = new Person("张三",9);
Person p2 = new Person("李四",9);
Person p3 = new Person("王五",67);
Person p4 = new Person("赵六",24);
//Set<Person> set8 = new TreeSet<Person>();
Set<Person> set8 = new TreeSet<Person>(new Person());
set8.add(p1);
set8.add(p2);
set8.add(p3);
set8.add(p4);
//System.out.println(set8);
//[com.qx.day10.Person@2db0f6b2, com.qx.day10.Person@3cd1f1c8, com.qx.day10.Person@3a4afd8d, com.qx.day10.Person@1996cd68]
for(Person p: set8){
System.out.println(p.name+" "+p.age);
}
- 对比普通数据类型,数据本身即为key,相同情况也是不重复保存
Set set7 = new TreeSet();
set7.add(7);
set7.add(98);
set7.add(98);
System.out.println(set7);
两种定制排序对比+自由改写理解(例如比较方法compare只返回1……)
自然排序与比较器排序对比
- 准备存储的三种不同类型的自定义类
-
- Student类,以属性id决定大小,实现自然排序
public class Student implements Comparable<Student>{
//学生,三个属性,姓名,年龄,学号
private String name;
private int age;
private int id;
public Student( int id,String name, int age){
this.name = name;
this.age = age;
this.id = id;
}
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return this.age;
}
public void setAge(int age){
this.age = age;
}
public int getId(){
return this.id;
}
//学号不会重复,所以以学号来决定大小
@Override
public int compareTo(Student o) {//o代表当前添加进来需要排序的元素,this代表集合中所有已经排序完成的元素
if(this.id > o.id){
return 1;//默认this大于o,o在前,this在后
}else if(this.id < o.id){
return -1;
}else{
return 0;
}
//return 0;
}
@Override
public String toString() {
//return super.toString();
return getClass().getName()+"[id="+id+",name="+name+",age="+age+"]";
}
}
//Student类继承接口Comparable<E>,实现方法compareTo(E o)
Student stu1 = new Student(2026,"学生1",15);
Student stu2 = new Student(2022,"学生2",23);
Student stu3 = new Student(2020,"学生3",35);
//1.自然排序的自定义类Student
//TreeSet
Set<Student> set1 = new TreeSet<>();
set1.add(stu1);
set1.add(stu2);
set1.add(stu3);
System.out.println(set1);
//TreeMap
Map<Student,Integer> map1 = new TreeMap<>();
map1.put(stu1,23);
map1.put(stu2,24);
map1.put(stu3,45);
System.out.println(map1);
- 运行结果如下
实现自然排序自定义类的TreeSet[com.qx.javaTest.Student[id=2020,name=学生3,age=35], com.qx.javaTest.Student[id=2022,name=学生2,age=23], com.qx.javaTest.Student[id=2026,name=学生1,age=15]]
实现自然排序自定义类的TreeMap{com.qx.javaTest.Student[id=2020,name=学生3,age=35]=45, com.qx.javaTest.Student[id=2022,name=学生2,age=23]=24, com.qx.javaTest.Student[id=2026,name=学生1,age=15]=23}
-
- MyData类,以属性data1决定大小,实现比较器
package com.qx.day10;
import java.util.Comparator;
public class MyData implements Comparator<MyData> {
public MyData(){
}
public MyData(int data1,String name, int data2){
this.data1 = data1;
this.name = name;
this.data2 = data2;
}
private String name;
private int data1;
private int data2;
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setData1(int data1){
this.data1 = data1;
}
public int getData1(){
return data1;
}
public void setData2(int data2){
this.data2 = data2;
}
public int getData2(){
return data2;
}
@Override
public int compare(MyData o1, MyData o2) {//理解新添加需要排序的元素是o1,已经排好序的元素s为o2
if(o1.data2 > o2.data2){
return 1;//默认,o1>o2,o2在前,o1在后
}else if(o1.data2 < o2.data2){
return -1;默认,o1<o2,o1在前,o2在后
}
else{
return 0;//相等
}
//添加顺序1,3,2,4.
//return 0;//1
//return 1;//1,3,2,4
//return -1;//4,2,3,1
//返回-1,默认o1<o2,o1排在o2之前
}
@Override
public String toString() {
//return super.toString();
return getClass().getName()+"[data1="+data1+",name="+name+",data2="+data2+"]";
}
}
//MyData类继承接口Comparator<E>,实现方法compare(E o1, E o2)
MyData d1 = new MyData(34,"数据1",56);
MyData d2 = new MyData(45,"数据2",6778);
MyData d3 = new MyData(23,"数据3",908);
//2.比较器排序的自定义类MyData,比较器类型的自定义类需要在new集合的时候提供该类对象作为参数
//TreeSet
Set<MyData> set2 = new TreeSet<>(new MyData());
set2.add(d1);
set2.add(d2);
set2.add(d3);
System.out.println("实现比较器排序的自定义类的TreeSet"+set2);
//TreeMap
Map<MyData,Student> map2 = new TreeMap<>(new MyData());
map2.put(d1,stu1);
map2.put(d2,stu2);
map2.put(d3,stu3);
System.out.println("实现比较器排序的自定义类的TreeMap"+map2);
- 运行结果
实现比较器排序的自定义类的TreeSet[com.qx.day10.MyData[data1=34,name=数据1,data2=56], com.qx.day10.MyData[data1=23,name=数据3,data2=908], com.qx.day10.MyData[data1=45,name=数据2,data2=6778]]
实现比较器排序的自定义类的TreeMap{com.qx.day10.MyData[data1=34,name=数据1,data2=56]=com.qx.javaTest.Student[id=2026,name=学生1,age=15], com.qx.day10.MyData[data1=23,name=数据3,data2=908]=com.qx.javaTest.Student[id=2020,name=学生3,age=35], com.qx.day10.MyData[data1=45,name=数据2,data2=6778]=com.qx.javaTest.Student[id=2022,name=学生2,age=23]}
-
- Puppy类
public class Puppy {
private int id;
private String name;
public Puppy(int id,String name){
this.name = name;
this.id = id;
}
public int getId(){
return this.id;
}
public void setId(int id){
this.id = id;
}
public String getNmae(){
return this.name;
}
public void setName(String name){
this.name = name;
}
@Override
public String toString() {
//return super.toString();
return getClass().getName()+"[id="+id+",name="+name+"]";
}
}
//Puppy类,普通类
Puppy p1 = new Puppy(8,"边牧");
Puppy p2 = new Puppy(4,"伯恩山");
Puppy p3 = new Puppy(3,"萨摩耶");
- 普通类,在集合new的时候传入比较器匿名对象,重写比较方法定制排序规则
//普通类Puppy,在集合new的时候传入匿名类实现普通自定义类的定制排序方法
//TreeSet
//自然排序不能这样写,因为本身就是重写在自定义类中直接使用,不需要传参
// Set<Puppy> set3 = new TreeSet<>(new Comparable<Puppy>(){
// @Override
// public int compareTo(Puppy o) {
// //return 0;
//
// }
// });
Set<Puppy> set3 = new TreeSet<Puppy>(new Comparator<Puppy>(){
@Override
public int compare(Puppy o1, Puppy o2) {
//return 0;
if(o1.getId() > o2.getId()){
return 1;
}else if(o1.getId() < o2.getId()){
return -1;
}else{
return 0;
}
}
});
set3.add(p1);
set3.add(p2);
set3.add(p3);
System.out.println("普通自定义类在new TreeMap时传匿名对象重写比较器"+set3);
//TreeMap,key和value都是自定义类的情况,
Map<Puppy,MyData> map3 = new TreeMap<>(new Comparator<Puppy>(){
@Override
public int compare(Puppy o1, Puppy o2) {
//return 0;
if(o1.getId() > o2.getId()){
return -1;
}else if(o1.getId() < o2.getId()){
return 1;
}else{
return 0;
}
}
});
map3.put(p1,d1);
map3.put(p2,d2);
map3.put(p3,d3);
System.out.println("普通自定义类在new TreeMap时传匿名对象重写比较器"+map3);
普通自定义类在new TreeMap时传匿名对象重写比较器[com.qx.javaTest.Puppy[id=3,name=萨摩耶], com.qx.javaTest.Puppy[id=4,name=伯恩山], com.qx.javaTest.Puppy[id=8,name=边牧]]
普通自定义类在new TreeMap时传匿名对象重写比较器{com.qx.javaTest.Puppy[id=8,name=边牧]=com.qx.day10.MyData[data1=34,name=数据1,data2=56], com.qx.javaTest.Puppy[id=4,name=伯恩山]=com.qx.day10.MyData[data1=45,name=数据2,data2=6778], com.qx.javaTest.Puppy[id=3,name=萨摩耶]=com.qx.day10.MyData[data1=23,name=数据3,data2=908]}
(脑洞)自由改写定制排序方法的返回情况(例如始终只return 1)
在方法compareTo(E o)和compare(E o1, E o2)中,比较大小时,this(o2)代表当前准备添加进来需要排序的元素,o(o1)代表集合中所有已经排序完成的元素。
- return 1 时,默认新添加的this(o2)大于o(o1),方法默认升序排序,o(o1)在前,this(o2)在后。
- return -1 时,默认新添加的this(o2)小于o(o1),方法默认升序排序,this(o2)在前,o(o1)在后。
- return 0 时,默认this(o2)等于o(o1)
默认都是升序,要降序可以使this(o2) < o1(o)时,return 1;this(o2)>o(o1),return -1。将排序o1(o)在前this(o2)在后,完成降序排序。
自由改写
- 假设方法始终只return 1 ,表示的含义则为新添加的this(o2)始终更大,排在后。集合为按照元素的添加顺序存储
- 假设方法只 return 0,表示所有添加进来的元素都相同,则只有集合为空时能存储一个元素。因为TreeSet和TreeMap的key都不可重复
- 假设方法只 return -1 ,表示的含义则为新添加的this(o2)始终更小,排在前。集合为按照元素的添加顺序的逆序存储
List
List与ArrayList
特点:
- 可以存储不同类型的数据
- 按照元素的添加顺序存储
- 存储的元素可重复
- 每个元素都有其对应的顺序索引
- ArrayList对象只能存储同一类型的元素
- ArrayList用法
- 可以存储重复元素,按照添加顺序设置元素索引
- 可以存储不同类型的元素
-
- List list1 = new ArrayList();//使用ArrayList
-
- list1.add(“b”);//添加元素,第一个添加的元素索引下标0
-
- list1.add(1,“iu”);//在指定索引位置1,插入元素"iu"
-
- list3.set(3,333);//改索引3位置元素为333
-
- System.out.println(list1.get(2));//通过索引来访问指定位置的集合元素
-
- list3.remove(0);//移除索引为0的元素
-
- list3.remove(“happy”);//移除元素happy
-
- System.out.println(list3.indexOf(“Taylor”));//查找元素在集合中第一次出现的索引下标
-
- System.out.println( list3.lastIndexOf(555));//查找元素最后一次出现的索引
-
- List sublist = list3.subList(4,6);//截取list3索引[4,6)的元素形成一个新集合。接去的时候,包含开始索引,不包含结束时索引
-
- System.out.println(list3.size());// 返回集合长度
-
- list1.clear();//清除集合
-
- System.out.println(list1);//打印集合
List<String> list1 = new ArrayList<String>();
list1.add("b");//索引下标0
list1.add("ulk");//下标1
list1.add("hyds");//下标2
list1.add("jh");//下标3
list1.add("b");
list1.add("ulk");
System.out.println(list1);
System.out.println(list1.get(2));//通过索引来访问指定位置的集合元素
list1.add(1,"iu");
System.out.println(list1);
list1.clear();
List list2 = new ArrayList();
list2.add("b");
list2.add(8);
System.out.println(list2);//[b, 8]
List list3 = new ArrayList();
list3.add("iu");
list3.add("Taylor");
list3.add('o');
list3.add(8);
list3.add(null);
list3.add("happy");
list3.add(8);
list3.add(555);
list3.add(5,555);
System.out.println(list3);
list3.remove(0);//移除索引为0的元素
System.out.println(list3);
list3.remove("happy");
System.out.println(list3);
System.out.println(list3.indexOf("Taylor"));//查找元素在集合中第一次出现的索引下标
System.out.println( list3.lastIndexOf(555));//查找元素最后一次出现的索引
list3.set(3,333);//改索引3位置元素为333
System.out.println(list3);
List sublist = list3.subList(4,6);//截取list3索引[4,6)的元素形成一个新集合。接去的时候,包含开始索引,不包含结束时索引
System.out.println(sublist);
ArrayList存储自定义类及定制排序
Map
- HashMap 用法
-
- map1.put(“b”,1);//添加数据
-
- System.out.println(map1.get(“b”));//根据key取值
-
- map1.remove(“c”);//根据key移除键值对
-
- System.out.println(map1.containsKey(“h”));//判断当前的map集合是否包含指定的key
-
- System.out.println(map1.containsValue(10));//判断当前的map集合是否包含指定的value
-
- Set keys = map1.keySet();//获取map集合的key的集合,return Set
-
- System.out.println(map1.values());//获取集合的所有value值,return Collection
-
- System.out.println(map1.size());//map集合的长度
-
- map.replace(“c”,67); 替换 hashMap 中是指定的 key 对应的 value。
-
- System.out.println(map1);//打印map
-
- map1.clear();//清空集合
Map<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("b",1);//添加数据
map1.put("c",2);
map1.put("e",2);
map1.put("f",8);
map1.put("h",0);
System.out.println(map1);
System.out.println(map1.get("b"));//根据key取值
map1.remove("c");//根据key移除键值对
System.out.println(map1);
System.out.println(map1.size());//map集合的长度
System.out.println(map1.containsKey("h"));//判断当前的map集合是否包含指定的key
System.out.println(map1.containsValue(10));//判断当前的map集合是否包含指定的value
//map1.clear();//清空集合
Set<String> keys = map1.keySet();//获取map集合的key的集合,return Set<E>
System.out.println(map1.values());//获取集合的所有value值,return Collection
//遍历map集合,通过map.keySet();
for(String key: keys){
System.out.print(key+"="+map1.get(key)+",");
}
-
- import java.util.Map.Entry;
-
- 3种遍历Map的方式
Set<String> keys = map1.keySet();//获取map集合的key的集合,return Set<E>
System.out.println(map1.values());//获取集合的所有value值,return Collection
//遍历1,存kay到set,再根据key取value
//遍历map集合,通过map.keySet();
for(String key: keys){
System.out.print(key+"="+map1.get(key)+",");//b=1,e=2,f=8,h=0,
}
System.out.println();
//返回映射的Set视图,直接输出
Set<Entry<String,Integer>> entrys = map1.entrySet();
System.out.println(entrys);//[b=1, e=2, f=8, h=0]
//for each输出
for(Entry<String,Integer> en: entrys){
System.out.println(en.getKey()+" = "+en.getValue());
}
HashMap & Hashtable
TreeMap
- TreeMap用法
-
- key不可重复,value可以重复
-
- 自动的根据key自然排序是字典排序
Map<Integer,String> map2 = new TreeMap<Integer,String>();
map2.put(4,"a");
map2.put(3,"a");
map2.put(2,"f");
//TreeMap的自然排序指字典排序
System.out.println(map2);
Map<String,String> map3 = new TreeMap<String,String>();
map3.put("ui","jh");
map3.put("u","78");
map3.put("ui","yh");//key不能重复
map3.put("hu","nj");
map3.put("gh","df");
System.out.println(map3);
TreeMap定制排序+key或value为自定义的类对象
- 尝试定义Map,key为PetShop对象表示一家宠物店,value为该店饲养宠物的名称。
-
- 定制排序,根据PetShop里养的宠物个数来进行排序
-
- 因为按照什么排序就会认定什么是key,所以宠物个数相同的对象无法重复存进TreeMap
-
- 定义四个对象,店1饲养8只布偶猫;店2饲养78只边牧;店3饲养7只萨摩耶;店4饲养24只布偶猫
import java.util.Comparator;
/**
* Created with IntelliJ IDEA.
*
* @Author: xuexuezi
* @Date: 2022/09/12/15:19
* @Description:
*/
public class PetShop implements Comparator<PetShop> {//import java.util.Comparator;
public PetShop(){
}
public PetShop(String shopName,int petNum){
this.shopName = shopName;
this.petNum = petNum;
}
private int petNum;
private String shopName;
public int getPetNum(){
return this.petNum;
}
public void setPetNum(int petNum){
this.petNum = petNum;
}
public void setShopName(String shopName){
this.shopName = shopName;
}
public String getShopName(){
return this.shopName;
}
@Override
public int compare(PetShop o1, PetShop o2) {
//return 0;
if(o1.petNum > o2.petNum){
return 1;//认为o1>o2,且排序由小到大
}else if(o1.petNum < o2.petNum){
return -1;
}else{
return 0;
}
}
}
注:定义的Map中key或value为自定义的类时,new TreeMap需要有参数,new一下这个类对象
Map<PetShop,String> map4 = new TreeMap<PetShop,String>(new PetShop());
PetShop s1 = new PetShop("店1",8);
PetShop s2 = new PetShop("店2",78);
PetShop s3 = new PetShop("店3",7);
PetShop s4 = new PetShop("店4",24);
map4.put(s1,"布偶猫");
map4.put(s2,"边牧");
map4.put(s3,"萨摩耶");
map4.put(s4,"布偶猫");
//遍历1
System.out.println(map4);
//遍历2
//存key
Set<PetShop> keys = map4.keySet();
for(PetShop k:keys){
System.out.println(k.getShopName()+" = "+map4.get(k));
}
//遍历3
Set<Entry<PetShop,String>> entrys = map4.entrySet();
System.out.println(entrys);
//遍历4
for(Entry<PetShop,String> e:entrys ){
System.out.println(e.getKey().getShopName()+"="+e.getValue());
}
- 四种遍历TreeMap的方法
关于Map的多种输出方式
构造一个HashMap<Integer,Pet>;构造一个TreeMap<Pet,String>其中Pet为自定义的类,表示我拥有的宠物类型
-
Pet属性:名称,数量,腿的个数
-
Pet方法: getter.setter,compare
-
Pet类实现接口Comparator,并实现方法compare来定义Pet的大小,从而在TreeMap中自然排序
-
- 其中用到了compareTo方法来比较String的大小
-
创建Pet类
import java.util.Comparator;
/**
* Created with IntelliJ IDEA.
*
* @Author: xuexuezi
* @Date: 2022/09/17/3:50
* @Description:
*/
public class Pet implements Comparator<Pet> {
//无参构造
public Pet(){
}
//有参构造
public Pet(String name,int num, int legNum){
this.name = name;
this.num = num;
this.legNum = legNum;
}
private String name;
private int num;
private int legNum;
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public int getNum(){
return this.num;
}
public void setNum(int num){
this.num = num;
}
public int getLeg(){
return this.legNum;
}
public void setLeg(int legNum){
this.legNum = legNum;
}
//以名字大小决定宠物大小
@Override
public int compare(Pet o1, Pet o2) {
if(o1.name.compareTo(o2.name) > 0){//指定的数o1.name>参数o2.name,返回正数
return 1;//得出o1>o2.并排在o2后
}else if(o1.name.compareTo(o2.name) < 0){//指定的数o1.name<o2.name,返回负数
return -1;
}else{//相等返回0
return 0;
}
}
- 构造一个HashMap<Integer,Pet>的map1
Pet pet1 = new Pet("边牧",1,4);
Pet pet2 = new Pet("缅因猫",2,4);
Pet pet3 = new Pet("鹦鹉",4,2);
Pet pet4 = new Pet("鲸鱼",1,0);
Map<Integer,Pet> map1 = new HashMap<Integer,Pet>();//该种宠物养了几只
map1.put(1,pet1);
map1.put(23,pet4);
map1.put(56,pet2);
map1.put(8,pet2);
map1.put(2,pet3);
- 构造一个一个TreeMap<Pet,String>的map2
//注意,以自定义的类为key时,需要在构造map时
Map<Pet,String> map2 = new TreeMap<Pet,String>(new Pet());//这类宠物性格特征
map2.put(pet1,"聪明");
map2.put(pet2,"温顺");
map2.put(pet3,"漂亮");
map2.put(pet4,"孤独");
遍历map
1.直接输出map的映射关系
- 由于对象直接输出会调用该类的toString方法,因为此处没有重写Object类的toString方法,所以输出对象会输出
类名+散列码
//1.直接遍历
System.out.println(map1);
System.out.println(map2);
输出结果如下:
{1=com.qx.day10.Pet@27ddd392, 2=com.qx.day10.Pet@19e1023e, 23=com.qx.day10.Pet@7cef4e59, 56=com.qx.day10.Pet@64b8f8f4, 8=com.qx.day10.Pet@64b8f8f4}
{com.qx.day10.Pet@64b8f8f4=温顺, com.qx.day10.Pet@27ddd392=聪明, com.qx.day10.Pet@7cef4e59=孤独, com.qx.day10.Pet@19e1023e=漂亮}
- 解决办法1:重写Object的toString方法后直接输出
@Override
public String toString() {
//return super.toString();
return getClass().getName()+"[name = "+name+",num = "+num+",legNum = "+legNum+"]";
}
输出结果如下:
{1=com.qx.day10.Pet[name = 边牧,num = 1,legNum = 4], 2=com.qx.day10.Pet[name = 鹦鹉,num = 4,legNum = 2], 23=com.qx.day10.Pet[name = 鲸鱼,num = 1,legNum = 0], 56=com.qx.day10.Pet[name = 缅因猫,num = 2,legNum = 4], 8=com.qx.day10.Pet[name = 缅因猫,num = 2,legNum = 4]}
{com.qx.day10.Pet[name = 缅因猫,num = 2,legNum = 4]=温顺, com.qx.day10.Pet[name = 边牧,num = 1,legNum = 4]=聪明, com.qx.day10.Pet[name = 鲸鱼,num = 1,legNum = 0]=孤独, com.qx.day10.Pet[name = 鹦鹉,num = 4,legNum = 2]=漂亮}
- 解决办法2:输出对象时,输出他的标志性属性例如名字
- 直接输出是自动输出键值对,无法做到
2. 用map.keySet返回key的Set集合;再通过方法map.get(key)获得value
- 此时因为map1和map2的键值对中都包含对象,所以输出对象.name来代表对象,而不是放任其自动输出散列码
//2.使用map.keySet()方法把所有key存入Set集合,再根据map.get()方法,根据key取到value
Set<Integer> key1 = map1.keySet();
for(Integer k1: key1){//此处,key为个数直接输出,vaule为对象,直接输出对象是散列码,最好是输出对象的名称
System.out.println(k1+" = "+map1.get(k1).name);
}
Set<Pet> key2 = map2.keySet();
for(Pet k2: key2){//此处,key为对象,输出对象的名称比较好
System.out.println(k2.name+" = "+map2.get(k2));
}
3.使用map.entrySet()方法,并使用Entry类的Set集合存放所有键值对(Entry内部类可以接收一个键值对)
1.用entry不是因为写起来简单,而是仅仅需要访问一次set里的所有元素即可
2.如果用上面的keySet(),要先访问所有的表key一次,再用key访问所有value一次,耗时是entry的两倍
- 导包
import java.util.Map.Entry;
Entry内部类来表示一个映射项,映射项包含Key和Value
//3.遍历3
Set<Entry<Integer,Pet>> entrys = map1.entrySet();
System.out.println(entrys);
Set<Entry<Pet,String>> entryss = map2.entrySet();
System.out.println(entryss);
- 输出如下
[1=com.qx.day10.Pet@27ddd392, 2=com.qx.day10.Pet@19e1023e, 23=com.qx.day10.Pet@7cef4e59, 56=com.qx.day10.Pet@64b8f8f4, 8=com.qx.day10.Pet@64b8f8f4]
[com.qx.day10.Pet@64b8f8f4=温顺, com.qx.day10.Pet@27ddd392=聪明, com.qx.day10.Pet@7cef4e59=孤独, com.qx.day10.Pet@19e1023e=漂亮]
4.遍历Entry类型的Set,使用Entry的getKey()和getValue()方法
//4.遍历Entry类型的Set,使用Entry的getKey()和getValue()方法
for(Entry<Integer,Pet> e: entrys){
System.out.println(e.getKey()+" = "+ e.getValue().name);
}
for(Entry<Pet,String> e: entryss){
System.out.println(e.getKey().name +" = "+e.getValue());
}
5.通过 lambda 表达式使用 forEach()
Lambda 表达式
Lamba的语法格式如下:
(parameters) -> expression
或
(parameters) ->{ statements; }
Lambda 表达式的简单例子:
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
HashMap forEach() 方法
forEach() 方法用于对 HashMap 中的每个映射执行指定的操作。
forEach() 方法的语法为:
hashmap.forEach(BiConsumer<K, V> action)
注: hashmap 是 HashMap 类的一个对象。
action - 要执行的操作
Lambda表达式内k,v随意起名。只是代表map中每个键值对的key和value
- 遍历5.通过 lambda 表达式使用 forEach()
map1.forEach((k,v)->{
System.out.print(k+"="+v.getName()+" ");
});
System.out.println();
map2.forEach((k,v)->{//Lambda表达式内k,v随意起名。只是代表map中每个键值对的key和value
System.out.print("key:"+k.getName()+"="+"value:"+v+" ");
});
Collection接口的含义
Collection接口是Set和List的父亲接口
Iterator接口,遍历TreeSet,HashSet,ArrayList
调用 it.next() 会返回迭代器的下一个元素,并且更新迭代器的状态。
调用 it.hasNext() 用于检测集合中是否还有元素。
调用 it.remove() 将迭代器返回的元素删除。
使用迭代器Iterator遍历
- Iterator遍历HashSet
//Iterator接口
Set<String> set1 = new HashSet<String>();
set1.add("ufo");
set1.add("jisoo");
set1.add("lisa");
Iterator<String> it1 = set1.iterator();
while(it1.hasNext()){
String i = it1.next();//每次执行都会返回下一个元素,并更新迭代器状态。如果是第一次执行,就返回第一个元素。
if(i.compareTo("ufo") == 0){
it1.remove();//删除迭代器返回的元素,如此时,返回的是==ufo的元素
}else{
System.out.println(i+" ");//不能使用it1.next()。因为会跳过当前元素,结果为lisa。正确结果为jisoo lisa
//理解这个更新迭代器状态意为,此时返回了第一个元素ufo并删除之后,第二次循环i走到第二个元素“jisoo”,如果输出时再调用一次it1.next()会直接越过i,只返回后一位“lisa”错误
}
}
- Iterator遍历TreeSet
//TreeSet
Set<Integer> set2 = new TreeSet<Integer>();
set2.add(56);
set2.add(9);
set2.add(56);
set2.add(6);
set2.add(99);
set2.add(78);
set2.add(87);
Iterator<Integer> it2 = set2.iterator();
while(it2.hasNext()){
Integer i = it2.next();
if(i < 60){//删除set2中 < 70的元素
it2.remove();
}
}
System.out.println(set2);
- Iterator遍历ArrayList
//ArrayList
List<Character> list = new ArrayList<Character>();
list.add('y');
list.add('t');
list.add('T');
list.add('k');
Iterator<Character> it3 = list.iterator();
while(it3.hasNext()){
if(it3.next() == 't'){//会删掉t,因为现在在y,但是返回后一位t,删除返回的这一位
it3.remove();
}
}
System.out.println(list);
注:remove必须在next方法之后调用,因为删除的就是返回的这一个元素
- 测试,调用两次next再remove,删除的是remove前最后一次返回的元素
//TreeSet
Set<Integer> set2 = new TreeSet<Integer>();
set2.add(9);
set2.add(56);
set2.add(6);
set2.add(99);
set2.add(78);
set2.add(87);
Iterator<Integer> it2 = set2.iterator();
while(it2.hasNext()){
System.out.println(it2.next());
System.out.println(it2.next());
it2.remove();
}
System.out.println(set2);
★Iterator调用多次出现的问题
- 调用多次,正常输出
- 循环中调用多次
- 错误出在,一次循环走两步,而每次进入循环的条件只能判断每次走的第一步是可走的,不越界的。
- 解决方法:因为循环体条件只判断迭代器是否存在元素,即next()方法返回的这一位元素的后一位是否空,只能判断下一位有。所以循环体内最多一次只走一步即可,走两步会在迭代器总共奇数个元素时越界。
Collections 工具类
工具:反转,随机排序,自然排序,定制排序,交换(List)
测试-基本数据类型的包装类,String,自定义类MyData三种元素类型存入集合时,使用这5种工具
- 自定义类MyData,属性:姓名,数据1,数据2
- 继承接口Comparator,并实现其比较大小的方法compare;此处用数据1的大小决定MyData的大小
import java.util.Comparator;
/**
* Created with IntelliJ IDEA.
*
* @Author: xuexuezi
* @Date: 2022/09/30/18:15
* @Description: 自定义类,我的数据类型
*/
public class MyData implements Comparator<MyData> {
public MyData(){
}
public MyData(String name,int data1, int data2){
this.name = name;
this.data1 = data1;
this.data2 = data2;
}
private String name;
private int data1;
private int data2;
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setData1(int data1){
this.data1 = data1;
}
public int getData1(){
return data1;
}
public void setData2(int data2){
this.data2 = data2;
}
public int getData2(){
return data2;
}
@Override
public int compare(MyData o1, MyData o2) {
if(o1.data1 > o2.data1){
return 1;
}else if(o1.data1 < o2.data1){
return -1;
}
else{
return 0;
}
}
}
1. Collections.reverse(List)反转元素顺序
- List元素为:8种基本数据类型的包装类,此处用Character和Double
-
- Integer,Character,Byte,Boolean,Short,Long,Float,Bouble
注意:集合中元素一定是类的对象,不能存放基本数据类型,而是存放他们的包装类
- Integer,Character,Byte,Boolean,Short,Long,Float,Bouble
List<Character> list = new ArrayList<Character>();
list.add('r');
list.add('y');
list.add('u');
list.add('h');
System.out.println(list);
//=====此处进行Collections 工具类反转,随机排序,自然排序,定制排序,交换5种测试======
Collections.reverse(list);
//==========================================================================
System.out.println(list);
List<Double> list0 = new ArrayList<Double>();
list0.add(7.9);
list0.add(45.765);
list0.add(67.9876);
list0.add(7.0);
System.out.println(list0);
//=====此处进行Collections 工具类反转,随机排序,自然排序,定制排序,交换5种测试======
Collections.reverse(list0);
//==========================================================================
System.out.println(list0);
- List元素为:String数据类型
List<String> list1 = new ArrayList<String>();
list1.add("ty");
list1.add("gth");
list1.add("frgg");
list1.add("haha");
list1.add("ha");
System.out.println(list1);
//=====此处进行Collections 工具类反转,随机排序,自然排序,定制排序,交换5种测试======
Collections.reverse(list1);
//==========================================================================
Collections.reverse(list1);
System.out.println(list1);
- List元素为:自定义类的对象(此处不涉及定制排序,因为List是按照添加元素顺序排序的,按原顺序反转即可)
- 并且MyData定制排序重写比较器compare时,以属性data1作为比较大小的标准
//创建存储自定义类的list
MyData d1 = new MyData("年,月",20,25);
MyData d2 = new MyData("时,分",18,31);
MyData d3 = new MyData("年龄,身高",24,168);
List<MyData> list2 = new ArrayList<MyData>();
list2.add(d1);
list2.add(d3);
list2.add(d2);
//用迭代器遍历输出对象的属性
Iterator<MyData> it = list2.iterator();
//System.out.println(it.next().getName()+it.next().getName()+it.next().getName());
while(it.hasNext()){
MyData i = it.next();//用i记录it.next()因为每调用一次next方法,迭代器都会返回下一位,并不会固定停留在某一位
System.out.println("name="+i.getName()+"; data1="+i.getData1()+"; data2="+i.getData2());
}
//=====此处进行Collections 工具类反转,随机排序,自然排序,定制排序,交换5种测试======
Collections.reverse(list2);
//==========================================================================
it = list2.iterator();
while (it.hasNext()) {
MyData i = it.next();//用i记录it.next()因为每调用一次next方法,迭代器都会返回下一位,并不会固定停留在某一位
System.out.println("name=" + i.getName() + "; data1=" + i.getData1() + "; data2=" + i.getData2());
}
2. Collections.shuffle(List)随机排序,即洗牌,打乱顺序
//=====此处进行Collections 工具类反转,随机排序,自然排序,定制排序,交换5种测试======
//替换上句反转所在位置即可
//==========================================================================
//反转
// Collections.reverse(list);
//洗牌
Collections.shuffle(list);
//反转
// Collections.reverse(list0);
//洗牌
Collections.shuffle(list0);
//反转
//Collections.reverse(list1);
//洗牌
Collections.shuffle(list1);
//反转
//Collections.reverse(list2);
//洗牌
Collections.shuffle(list2);
- 洗牌后效果
3. Collections.sort(List)根据字典,升序排序。也称自然排序
//反转
// Collections.reverse(list);
//洗牌
//Collections.shuffle(list);
//升序排序
Collections.sort(list);
//反转
// Collections.reverse(list0);
//洗牌
//Collections.shuffle(list0);
//升序排序
Collections.sort(list0);
//反转
//Collections.reverse(list1);
//洗牌
// Collections.shuffle(list1);
//升序排序
Collections.sort(list1);
- 自然升序排序效果
4. Collections.sort(List,Comparator)根据自定大小排序| list.sort(Comparator)
Collections.sort(list2,new MyData());
或MyData data = new MyData();Collections.sort(list2,data);
调用都可以,第二个参数要传一个自定义类的对象,一般用匿名对象
类名称 对象名 = new 类名称();
每次 new 都相当于开辟了一个新的对象,并开辟了一个新的物理内存空间。如果一个对象只需要使用唯一的一次,就可以使用匿名对象,匿名对象还可以作为实际参数传递。
匿名对象就是没有明确的给出名字的对象,是对象的一种简写形式。一般匿名对象只使用一次,而且匿名对象只在堆内存中开辟空间,而不存在栈内存的引用。
//创建存储自定义类的list
MyData d1 = new MyData("年,月",20,25);
MyData d2 = new MyData("时,分",18,31);
MyData d3 = new MyData("年龄,身高",24,168);
List<MyData> list2 = new ArrayList<MyData>();
list2.add(d1);
list2.add(d3);
list2.add(d2);
//用迭代器遍历输出对象的属性
Iterator<MyData> it = list2.iterator();
//System.out.println(it.next().getName()+it.next().getName()+it.next().getName());
while(it.hasNext()){
MyData i = it.next();//用i记录it.next()因为每调用一次next方法,迭代器都会返回下一位,并不会固定停留在某一位
System.out.println("name="+i.getName()+"; data1="+i.getData1()+"; data2="+i.getData2());
}
//反转
//Collections.reverse(list2);
//洗牌
//Collections.shuffle(list2);
//升序排序
MyData data = new MyData();
Collections.sort(list2,data);
it = list2.iterator();
while (it.hasNext()) {
MyData i = it.next();//用i记录it.next()因为每调用一次next方法,迭代器都会返回下一位,并不会固定停留在某一位
System.out.println("name=" + i.getName() + "; data1=" + i.getData1() + "; data2=" + i.getData2());
}
- 根据比较器的自定义大小排序
- 直接用 list.sort排序也可以
public static class NodeComp implements Comparator<Node>{
@Override
public int compare(Node o1, Node o2) {
return o1.value - o2.value;
}
}
ArrayList<Node> list = new ArrayList<>();
list.sort(new NodeComp());//排序list内存储的节点
// 这两个都可以,Collections.sort(list, new NodeComp());
5. swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
- 注意:int表示要交换的两个元素在list中的下标,不可越界。下标第一个元素从0开始
//反转
// Collections.reverse(list);
//洗牌
//Collections.shuffle(list);
//升序排序
// Collections.sort(list);
//交换
Collections.swap(list,0,3);
//反转
// Collections.reverse(list0);
//洗牌
//Collections.shuffle(list0);
//升序排序
//Collections.sort(list0);
//交换
Collections.swap(list0,0,3);
//反转
//Collections.reverse(list1);
//洗牌
// Collections.shuffle(list1);
//升序排序
//Collections.sort(list1);
//交换
Collections.swap(list1,0,3);
//反转
//Collections.reverse(list2);
//洗牌
//Collections.shuffle(list2);
//升序排序
// MyData data = new MyData();
// Collections.sort(list2,data);
//交换
Collections.swap(list2,0,2);
- 交换结果
工具:返回最大值,最小值(分为自然排序和定制排序两种不同的大小判断)返回元素出现次数,新值代替旧值(List,TreeSet,HashSet)
关于Collection集合类的继承树如下图,图片转自java集合Collection常用方法详解
- 构造所用集合
- MyData类定义见前上一小标题: 工具:反转,随机排序,自然排序,定制排序,交换(List)
MyData d1 = new MyData(20, "年,月", 4);
MyData d2 = new MyData(18, "时,分", 31);
MyData d3 = new MyData(24, "年龄,身高", 168);
MyData d4 = new MyData(168, "身高,体重", 75);
List<Integer> list1 = new ArrayList<Integer>();
List<MyData> list2 = new ArrayList<>();
Set<Character> hset1 = new HashSet<>();
Set<MyData> hset2 = new HashSet<>();
Set<Double> tset1 = new TreeSet<>();
Set<MyData> tset2 = new TreeSet<>();
list1.add(8);
list1.add(67);
list1.add(345);
list1.add(9);
list2.add(d1);
list2.add(d2);
list2.add(d3);
hset1.add('a');
hset1.add('b');
hset1.add('c');
hset2.add(d1);
hset2.add(d2);
hset2.add(d3);
tset1.add(4.6);
tset1.add(9.674);
tset1.add(1.0);
tset2.add(d1);
tset2.add(d2);
tset2.add(d3);
- 创建类Student
public class Student {
private int id;
private String name;
public Student(){
}
public Student(int id, String name){
this.id = id;
this.name = name;
}
public void setId(int id){
this.id = id;
}
public int getId(){
return this.id;
}
public void setNmae(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}
Object max(Collection)
根据元素的自然顺序,返回给定集合中的最大元素
- List元素为:8种基本数据类型的包装类和String
-
- Integer,Character,Byte,Boolean,Short,Long,Float,Bouble
注意:集合中元素一定是类的对象,不能存放基本数据类型,而是存放他们的包装类
- Integer,Character,Byte,Boolean,Short,Long,Float,Bouble
//1. Object max(Collection)根据元素的自然顺序,返回给定集合中的最大元素
System.out.println("打印list1,为存储Integer元素的ArrayList"+list1);
System.out.println("list1的max:"+Collections.max(list1));
打印list1,为存储Integer元素的ArrayList[8, 67, 345, 9]
list1的max:345
- HashSet元素为:8种基本数据类型的包装类和String
System.out.println("打印hset1,为存储Character元素的HashSet"+hset1);
System.out.println("hset1的max:"+Collections.max(hset1));
打印hset1,为存储Character元素的HashSet[a, b, c]
hset1的max:c
- TreeSet元素为:8种基本数据类型的包装类和String
System.out.println("打印tset1,为存储Double元素的TreeSet"+tset1);
System.out.println("tset的max:"+Collections.max(tset1));
打印tset1,为存储Double元素的TreeSet[1.0, 4.6, 9.674]
tset的max:9.674
Object max(Collection,Comparator)
根据Comparator指定的顺序,返回给定集合中的最大元素
- List元素为:MyData自定义类对象
注: 比较器参数的两种写法
//2.Object max(Collection,Comparator)根据Comparator指定的顺序,返回给定集合中的最大元素
//
System.out.println("打印list2,为存储MyData元素的ArrayList"+list2);
// Iterator<MyData> it1 = list2.iterator();
// while(it1.hasNext()){
// System.out.print(it1.next()+" ");
// }
// System.out.println();
//写法一:自定义类中有重写比较器
System.out.println("list2的max的data1:"+Collections.max(list2, new MyData()).getData1());
//写法二:普通类,在参数部分重写
//本身ArrayList存储的元素是不需要定制排序的,但是这个方法需要
List<Student> list3 = new ArrayList<Student>();
list3.add(new Student(01,"张三"));
list3.add(new Student(02,"李四"));
list3.add(new Student(03,"王五"));
System.out.println("打印list3,为存储Student的ArryList"+list3);
System.out.println("list3的max的id:"+Collections.max(list3,new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//return 0;
if (o1.getId() > o2.getId()) {
return 1;//升序
} else if (o1.getId() < o2.getId()) {
return -1;
} else {
return 0;
}
}
}).getId());
打印list2,为存储MyData元素的ArrayList[com.qx.day10.MyData[data1=20,name=年,月,data2=4], com.qx.day10.MyData[data1=18,name=时,分,data2=31], com.qx.day10.MyData[data1=24,name=年龄,身高,data2=168]]
list2的max的data1:24
打印list3,为存储Student的ArryList[com.qx.day10.Student[id=1,name=张三], com.qx.day10.Student[id=2,name=李四], com.qx.day10.Student[id=3,name=王五]]
list3的max的id:3
- HashSet元素为:MyData自定义类对象
System.out.println("打印hset2,为存储MyData元素的HashSet"+hset2);
System.out.println("hset2的max的data1:" + Collections.max(hset2, new MyData()).getData1());
打印hset2,为存储MyData元素的HashSet[com.qx.day10.MyData[data1=24,name=年龄,身高,data2=168], com.qx.day10.MyData[data1=20,name=年,月,data2=4], com.qx.day10.MyData[data1=18,name=时,分,data2=31]]
hset2的max的data1:24
- TreeSet元素为:MyData自定义类对象
System.out.println("打印tset2,为存储MyData元素的TreeSet"+tset2);
System.out.println("tset2的max的data1:" + Collections.max(tset2, new MyData()).getData1());
打印tset2,为存储MyData元素的TreeSet[com.qx.day10.MyData[data1=20,name=年,月,data2=4], com.qx.day10.MyData[data1=18,name=时,分,data2=31], com.qx.day10.MyData[data1=24,name=年龄,身高,data2=168]]
tset2的max的data1:24
Object min(Collection)
根据元素的自然顺序,返回给定集合中的最小元素
- List元素为:8种基本数据类型的包装类和String
System.out.println("打印list1,为存储Integer元素的ArrayList" + list1);
System.out.println("list1的min:" + Collections.min(list1));
打印list1,为存储Integer元素的ArrayList[8, 67, 345, 9]
list1的min:8
- HashSet元素为:8种基本数据类型的包装类和String
System.out.println("打印hset1,为存储Character元素的HashSet" + hset1);
System.out.println("hset1的min:" + Collections.min(hset1));
打印hset1,为存储Character元素的HashSet[a, b, c]
hset1的min:a
- TreeSet元素为:8种基本数据类型的包装类和String
System.out.println("打印tset1,为存储Double元素的TreeSet"+tset1);
System.out.println("tset的min:"+Collections.min(tset1));
打印tset1,为存储Double元素的TreeSet[1.0, 4.6, 9.674]
tset的min:1.0
Object min(Collection, Comparator)
根据Comparator指定的顺序,返回给定集合中的最小元素
- List元素为:MyData自定义类对象
System.out.println("打印tset2,为存储MyData元素的TreeSet"+list2);
System.out.println("list2的min的data1:"+Collections.min(list2, new MyData()).getData1());
打印tset2,为存储MyData元素的TreeSet[com.qx.day10.MyData[data1=20,name=年,月,data2=4], com.qx.day10.MyData[data1=18,name=时,分,data2=31], com.qx.day10.MyData[data1=24,name=年龄,身高,data2=168]]
list2的min的data1:20
- HashSet元素为:MyData自定义类对象
System.out.println("打印hset2,为存储MyData元素的HashSet"+hset2);
System.out.println("hset2的min的data1:"+Collections.min(hset2,new MyData()).getData1());
打印hset2,为存储MyData元素的HashSet[com.qx.day10.MyData[data1=24,name=年龄,身高,data2=168], com.qx.day10.MyData[data1=20,name=年,月,data2=4], com.qx.day10.MyData[data1=18,name=时,分,data2=31]]
hset2的min的data1:20
- TreeSet元素为:MyData自定义类对象
System.out.println("打印tset2,为存储MyData元素的TreeSet"+hset2);
System.out.println("tset2的min的data1:"+Collections.min(tset2,new MyData()).getData1());
打印tset2,为存储MyData元素的TreeSet[com.qx.day10.MyData[data1=24,name=年龄,身高,data2=168], com.qx.day10.MyData[data1=20,name=年,月,data2=4], com.qx.day10.MyData[data1=18,name=时,分,data2=31]]
tset2的min的data1:20
int frequency(Collection,Object)
返回指定集合中指定元素的出现次数
- List元素为:8种基本数据类型的包装类,此处用Character和Double
list1.add(96);
list1.add(96);
System.out.println("打印list1,为存储Integer元素的ArrayList" + list1);
System.out.println("list1的96出现次数:" + Collections.frequency(list1,96));
打印list1,为存储Integer元素的ArrayList[8, 67, 345, 9, 96, 96]
list1的96出现次数:2
- HashSet元素为:8种基本数据类型的包装类和String数据类型
注: HashSet和TreeSet无法存储重复元素 ,所以该方法在这两个集合中只会返回0,1
System.out.println("打印hset1,为存储Character元素的HashSet" + hset1);
System.out.println("hset1的'u:出现次数" + Collections.frequency(hset1,'u'));
打印hset1,为存储Character元素的HashSet[a, b, c]
hset1的'u:出现次数0
- TreeSet元素为:8种基本数据类型的包装类和String数据类型
tset1.add(5.8);
tset1.add(5.8);
System.out.println("打印tset1,为存储Double元素的TreeSet"+tset1);
System.out.println("tset的5.8出现次数:"+Collections.frequency(tset1,5.8));
打印tset1,为存储Double元素的TreeSet[1.0, 4.6, 5.8, 9.674]
tset的5.8出现次数:1
- List元素为:MyData自定义类对象
发现: 统计出现次数时,要求元素一定是同一个对象,这里的同一个指必须要是这个对象(用get(index)来访问之前有添加的对象,哪怕修改了属性也依然算是这个对象。
创建两个对象属性都相同也不是同一个对象。
list2.add(new MyData(11,"一",78));//index 3
list2.add(new MyData(11,"呵呵",78));//4
list2.add(new MyData(11,"一",78));//5
list2.add(new MyData(11,"一",67));//6
list2.add(list2.get(3));
list2.add(list2.get(5));
//在下一次添加索引5的对象之前修改他的属性
list2.get(5).setData1(700);
list2.add(list2.get(5));
System.out.println("打印list2,为存储MyData元素的TreeSet"+list2);
System.out.println("list2的new MyData(11,\"一\",78)的出现次数:"+Collections.frequency(list2, new MyData(11,"一",78)));
System.out.println("list2的list2.get(5)的出现次数"+Collections.frequency(list2,list2.get(5) ));
打印list2,为存储MyData元素的TreeSet[com.qx.day10.MyData[data1=20,name=年,月,data2=4], com.qx.day10.MyData[data1=18,name=时,分,data2=31], com.qx.day10.MyData[data1=24,name=年龄,身高,data2=168], com.qx.day10.MyData[data1=11,name=一,data2=78], com.qx.day10.MyData[data1=11,name=呵呵,data2=78], com.qx.day10.MyData[data1=11,name=一,data2=78], com.qx.day10.MyData[data1=11,name=一,data2=67], com.qx.day10.MyData[data1=11,name=一,data2=78], com.qx.day10.MyData[data1=11,name=一,data2=78], com.qx.day10.MyData[data1=11,name=一,data2=78]]
list2的new MyData(11,"一",78)的出现次数:0
list2的list2.get(5)的出现次数:3
- HashSet元素为:MyData自定义类对象
要查找对象,但是没有索引可以取,只能用max,min取对象
hset2.add(Collections.max(hset2,new MyData()));
System.out.println("打印hset2,为存储MyData元素的HashSet"+hset2);
System.out.println("hest2的data1的max的出现次数:"+Collections.frequency(hset2, Collections.max(hset2,new MyData())));
打印hset2,为存储MyData元素的HashSet[com.qx.day10.MyData[data1=24,name=年龄,身高,data2=168], com.qx.day10.MyData[data1=20,name=年,月,data2=4], com.qx.day10.MyData[data1=18,name=时,分,data2=31]]
hest2的data1的max的出现次数:1
- TreeSet元素为:MyData自定义类对象
没意义,反正只会返回1或0
System.out.println("打印tset2,为存储MyData元素的TreeSet"+hset2);
System.out.println("tset2的new MyData(11,\"一\",78)的出现次数:"+Collections.frequency(tset2, new MyData(11,"一",78)));
打印tset2,为存储MyData元素的TreeSet[com.qx.day10.MyData[data1=24,name=年龄,身高,data2=168], com.qx.day10.MyData[data1=20,name=年,月,data2=4], com.qx.day10.MyData[data1=18,name=时,分,data2=31]]
tset2的new MyData(11,"一",78)的出现次数:0
boolean replaceAll(List list,Object oldVal,newVal)
使用新值代替
- List元素为:8种基本数据类型的包装类和String数据类型
list1.add(8);
list1.add(8);
list1.add(8);
System.out.println("打印list1,为存储Integer元素的ArrayList"+list1);
System.out.println("用888代替8,"+Collections.replaceAll(list1,8,888)+"->"+list1);
打印list1,为存储Integer元素的ArrayList[8, 67, 345, 9, 96, 96, 8, 8, 8]
用888代替8,true->[888, 67, 345, 9, 96, 96, 888, 888, 888]
- List元素为:MyData自定义类对象
list2.add(list2.get(0));
list2.add(list2.get(0));
System.out.println("打印list2,为存储MyData元素的ArrayList"+list2);
System.out.println("用MyData[data1=22,name=年,月,data2=10]代替对象索引为0的MyData[data1=20,name=年,月,data2=4],"+Collections.replaceAll(list2,list2.get(0),new MyData(22,"年,月",10))+"->"+list2);
打印list2,为存储MyData元素的ArrayList[com.qx.day10.MyData[data1=20,name=年,月,data2=4], com.qx.day10.MyData[data1=18,name=时,分,data2=31], com.qx.day10.MyData[data1=24,name=年龄,身高,data2=168], com.qx.day10.MyData[data1=11,name=一,data2=78], com.qx.day10.MyData[data1=11,name=呵呵,data2=78], com.qx.day10.MyData[data1=700,name=一,data2=78], com.qx.day10.MyData[data1=11,name=一,data2=67], com.qx.day10.MyData[data1=11,name=一,data2=78], com.qx.day10.MyData[data1=700,name=一,data2=78], com.qx.day10.MyData[data1=700,name=一,data2=78], com.qx.day10.MyData[data1=20,name=年,月,data2=4], com.qx.day10.MyData[data1=20,name=年,月,data2=4]]Disconnected from the target VM, address: '127.0.0.1:4127', transport: 'socket'
用MyData[data1=22,name=年,月,data2=10]代替对象索引为0的MyData[data1=20,name=年,月,data2=4],true->[com.qx.day10.MyData[data1=22,name=年,月,data2=10], com.qx.day10.MyData[data1=18,name=时,分,data2=31], com.qx.day10.MyData[data1=24,name=年龄,身高,data2=168], com.qx.day10.MyData[data1=11,name=一,data2=78], com.qx.day10.MyData[data1=11,name=呵呵,data2=78], com.qx.day10.MyData[data1=700,name=一,data2=78], com.qx.day10.MyData[data1=11,name=一,data2=67], com.qx.day10.MyData[data1=11,name=一,data2=78], com.qx.day10.MyData[data1=700,name=一,data2=78], com.qx.day10.MyData[data1=700,name=一,data2=78], com.qx.day10.MyData[data1=22,name=年,月,data2=10], com.qx.day10.MyData[data1=22,name=年,月,data2=10]]
集合练习
编程题
一,map的遍历,插入,删除,替换
一、现在有一个map集合如下:
HashMap<Integer,String> map = new HashMap<Integer, String>();
map.put(1, "张三丰");
map.put(2, "周芷若");
map.put(3, "汪峰");
map.put(4, "灭绝师太");
要求:
1.遍历集合,并将序号与对应人名打印。
2.向该map集合中插入一个编码为5姓名为李晓红的信息
3.移除该map中的编号为1的信息
4.将map集合中编号为2的姓名信息修改为"周林"
- 1.遍历集合,并将序号与对应人名打印。
public static void main(String[] args){
HashMap<Integer,String> map = new HashMap<Integer,String>();
map.put(1,"张三丰");
map.put(2,"周芷若");
map.put(3,"汪峰");
map.put(4,"灭绝师太");
//遍历集合
//遍历1,直接输出
System.out.println("遍历1,直接输出");
System.out.println(map);
//遍历2,map.keySet返回key的Set集合;再map.get(key)获得value
System.out.println("遍历2,map.keySet返回key的Set集合;再map.get(key)获得value");
Set<Integer> key = map.keySet();
for(Integer k: key){
System.out.println(k+"="+map.get(k)+" ");
}
//遍历3.使用map.entrySet()方法,并使用Entry类的Set集合存放所有键值对
System.out.println("遍历3.使用map.entrySet()方法,并使用Entry类的Set集合存放所有键值对");
Set<Entry<Integer,String>> entrys = map.entrySet();
System.out.println(entrys);
//遍历4.遍历Entry类型的Set,使用Entry的getKey()和getValue()方法
System.out.println("遍历4.遍历Entry类型的Set,使用Entry的getKey()和getValue()方法");
for(Entry<Integer,String> e:entrys){
System.out.println(e.getKey()+"="+e.getValue());
}
}
- 2.向该map集合中插入一个编码为5姓名为李晓红的信息
map.put(5,"李晓红");
System.out.println(map);
- 3.移除该map中的编号为1的信息
map.remove(1);
System.out.println(map);
- 4.将map集合中编号为2的姓名信息修改为"周林"
map.replace(2,"周林");//替换指定的key对应value
//map.put(2,"周林");//小技巧,可以直接添加。因为如果key存在,就会替换这个key的value
System.out.println(map);
注:只修改value,确认key已经存在的情况下,可以直接使用添加put。key重复的情况下只会刷新value的值
二、根据两个数组元素构造map并遍历
二、有2个数组,第一个数组内容为:[黑龙江省,浙江省,江西省,广东省,福建省],
第二个数组内容为:[哈尔滨,杭州,南昌,广州,福州],
将第一个数组元素作为key,第二个数组元素作为value存储到Map集合中。
如{黑龙江省=哈尔滨, 浙江省=杭州, …}。
使用两种方式遍历map集合
String[] arr1 = {"黑龙江省","浙江省","江西省","广东省","福建省"};
String[] arr2 = {"哈尔滨","杭州","南昌","广州","福州"};
Map<String,String> map = new TreeMap<>();
for(int i=0; i<arr1.length && i<arr2.length; i++){
map.put(arr1[i],arr2[i]);
}
//遍历1,直接输出
System.out.println(map);
//遍历2,Set存储key
Set<String> key = map.keySet();
for(String k:key){
System.out.println(k+"="+map.get(k));
}
//遍历3,entry类
Set<Entry<String,String>> entrys = map.entrySet();
System.out.println(entrys);
//遍历4,entry类foreach
for(Entry<String,String> e:entrys){
System.out.println(e);
}
三,统计输入字符,每种字符的个数
三、分析以下需求,并用代码实现
1.利用键盘录入,输入一个字符串
2.统计该字符串中各个字符的数量(提示:字符不用排序)
3.如:
用户输入字符串"If~you-want~to~change-your_fate_I_think~you~must~come-to-the-dark-horse-to-learn-java"
程序输出结果:
-(9)I(2)_(3)a(7)c(2)d(1)e(6)f(2)g(1)h(4)i(1)j(1)k(2)l(1)m(2)n(4)o(8)r(4)s(2)t(8)u(4)v(1)w(1)y(3)~(6)
- 方法一: 创建一个178大小的数组,因为ASCII码表的范围为0-177,默认赋值全为0。将数组下标作为字符的ASCII码值,每个位置对应的字符出现一次,数组元素就+1。
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入字符串");
String str = "";//空字符串
try {
str = buffer.readLine();
} catch (Exception e) {
e.printStackTrace();
}
char[] arr = str.toCharArray();
int[] ascii = new int[178];//默认值全为0
for (int i=0; i < arr.length; i++) {
//遍历字符数组,检索字符个数
ascii[arr[i]]++;//每检索到一个字符就在对应位置++
}
for(int i=0; i<ascii.length; i++){
if(ascii[i] != 0){
System.out.print((char)i+"("+ascii[i]+")");
}
}
- 方法二: 用Map,每读到一个字符,就作为key存储,value为出现次数,随着读取增加。
注: 区分统计个数时,字符第一次出现,不可用map3.put(arr4[i],map3.get(arr4[i])+1);
因为此时get(key)中key不存在,返回出错
//用Map组建对应关系
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入字符串");
String str2="";//如果不赋值,因为不确定try中能否成功赋值。toCharArray时字符有空的可能,编译出错。
try{
str2 = buf.readLine();
}catch(Exception e){
e.printStackTrace();
}
//注意到,元素不装箱,依然可以正常将char类型的元素赋值给类型为Character的key
//因为自动装箱
char[] arr4 = str2.toCharArray();
// //将元素装箱
// char[] arr3 = str2.toCharArray();
// Character[] arr4 = new Character[arr3.length];
// for(int i=0; i<arr3.length; i++){
// arr4[i] = new Character(arr3[i]);
// }
//读到字符数组以后,构造Map
Map<Character,Integer> map3 = new TreeMap<>();
for(int i=0; i<arr4.length; i++){
//每读到一个字符就输入,因为key重复的话只刷新value,所以直接put,value++即可
//如果读到新字符,get(key)将无法获取value,注意区分
if(map3.containsKey(arr4[i])){
map3.put(arr4[i],map3.get(arr4[i])+1);
}else{
map3.put(arr4[i],1);
}
}
- char赋值给Character为自动装箱,不需要在进行操作
//map的5种遍历方式
System.out.println("1.map3直接输出");
System.out.println(map3);
System.out.println("2.keySet()方法遍历key+get(key)获得value");
Set<Character> key3 = map3.keySet();
for(Character k: key3){
System.out.print(k+"("+map3.get(k)+")");
}
System.out.println();
System.out.println("3.entry类型接收map的entrySet方法,一个entry类对象相当于一个键值对。直接输出entrySet");
Set<Entry<Character,Integer>> entrys3= map3.entrySet();
System.out.println(entrys3);
System.out.println("4.for each输出entrySet");
Set<Entry<Character,Integer>> entrys4= map3.entrySet();
for(Entry<Character,Integer> e:entrys4){
System.out.print(e.getKey()+"("+e.getValue()+")");
}
System.out.println();
System.out.println("5.Lambde表达式forEach输出");
map3.forEach((k,v)->{
System.out.print(k+"("+v+")");
});