javaAPI之集合集合comparator和comparable

本文详细介绍了Java集合中的排序方法(Collections.sort)及排序规则实现,包括Comparable和Comparator接口的应用,以及队列(Queue)、栈(Stack)和查找表(Map)的基本概念和使用方法,特别强调了如何对集合进行降序排列和Map集合的遍历。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.之前集合没有整理完,接着整理,大家可以连起之前的一起参考

2.1 List排序
• Collections是集合的工具类,它提供了很多便于我们操作集合的方法,其中就有用于集合排序的sort方法。
• 该方法定义为: void sort(List list)
该方法的作用是对给定的集合元素进行自然排序。

Comparable:接口
• Collections的sort方法是对集合元素进行自然排序,那么两个元素对象之间就一定要有大小之分。这个大小之分是如何界定的?实际上,在使用Collections的sort排序的集合元素都必须是Comparable接口的实现类,该接口表示其子类是可比较的,因为实现该接口必须重写抽象方法:
– int compareTo(T t);
该方法用于使当前对象与给定对象进行比较。
– 若当前对象大于给定对象,那么返回值应为>0的整数。
– 若小于给定对象,那么返回值应为<0的整数。
– 若两个对象相等,则应返回0。
Comparable接口:内比较器
如果一个类实现了此接口,那么一定要重写compareTo(Object obj),在此方法中,将比较规则写出。
之后才可以调用Collections.sort(list)

Collections.sort(list)
案例:
一个集合中存放的是学生对象,现对集合进行排序,排序规则按照学生的学号排序

方式一:通过让student类实现Comparable接口
      public class Student implements Comparable<Student> {
   private int schooleId;
   private int age;
   private String name;
   public Student() {
      super();
      // TODO Auto-generated constructor stub
   }
   public Student(int schooleId, int age, String name) {
      super();
      this.schooleId = schooleId;
      this.age = age;
      this.name = name;
   }
   public int getSchooleId() {
      return schooleId;
   }
   public void setSchooleId(int schooleId) {
      this.schooleId = schooleId;
   }
   public int getAge() {
      return age;
   }
   public void setAge(int age) {
      this.age = age;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   @Override
   public String toString() {
      return "Student [schooleId=" + schooleId + ", age=" + age + ", name=" + name + "]";
   }
   @Override
   public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + schooleId;
      return result;
   }
   @Override
   public boolean equals(Object obj) {
      if (this == obj)
         return true;
      if (obj == null)
         return false;
      if (getClass() != obj.getClass())
         return false;
      Student other = (Student) obj;
      if (schooleId != other.schooleId)
         return false;
      return true;
   }
   @Override
   public int compareTo(Student o) {
      //比较两个学生的学号
//    int schoolId1 = o.getSchooleId();
      return this.schooleId - o.getSchooleId();
   }
此排序默认升序,如果想默认降序,可以在前边加“-”或者调整一下两者的位置
  
  
 
}
public class StudentTest {
   public static void main(String[] args) {
      /*
       * 创建一个集合用于保存学生对象
       */
      List<Student> list =
            new ArrayList<Student>();
     
      //创建三个学生对
象
      Student stu1 = new Student(1004, 23, "张三");
      Student stu2 = new Student(1001, 23, "李四");
      Student stu3 = new Student(1003, 23, "王五");
     
      list.add(stu1);
      list.add(stu2);
      list.add(stu3);
     
      System.out.println(list);
     
      //要求对集合中的学生对象进行排序,规则是按照学号
      Collections.sort(list);
     
      System.out.println(list);
   }
 
}

要求:
前提:以上题为前提
集合中保存学生对象,现要按照学生的年龄排序

Comparator:接口
• 一旦Java类实现了Comparable接口,其比较逻辑就已经确定;如果希望在排序的操作中临时指定比较规则,可以采用Comparator接口回调的方式。
• Comparator接口要求实现类必须重写其定义的方法:int compare(T o1,T o2)

Comparator:外比较器:
使用场景:
如果对一个集合中进行排序时,不想用集合中元素已有的排序规则,而是要用自定义规则,此时需要写一个类实现Comparator接口,重写其compare(T o1,T o2)。在主方法所在类的内部类中重写
在对集合排序时调用Collections.sort(List,Comparator)

   /**
 * 对集合中的学生对象按照年龄排序
 * @author adminitartor
 *
 */
public class StudentAgeTest {
   public static void main(String[] args) {
      /*
       * 创建集合用于保存Student对象
       */
      List<Student> list =
             new ArrayList<Student>();
     
      //创建三个学生对象
      Student stu1 = new Student(1004, 28, "张三");
      Student stu2 = new Student(1001, 23, "李四");
      Student stu3 = new Student(1003, 24, "王五");
     
      list.add(stu1);
      list.add(stu2);
      list.add(stu3);
     
      System.out.println(list);
     
      /*
       * 对集合进行排序 ,按照年龄
       */
      StudentAgeTest ageTest =
            new StudentAgeTest();
       
      Collections.sort(list, ageTest.new ByAge());
     
      System.out.println(list);
   }
  
  
  
  
   //内部类
   /*
    * Comparator:外比较器
    * 写了一个比较器,只不过这个比较器是写在Student
    * 封装类的外部的
    */
   private class ByAge implements Comparator<Student>{
 
      @Override
      public int compare(Student o1, Student o2) {
         return o1.getAge()-o2.getAge();
同样是默认升序,如果要降序的话,前边加“-”或者换一下位置
      }
     
   }
 
}

Comparabl与Comparator的区别
Comparable:接口,内比较器
使用:
1, 一个类实现此接口
2, 重写compareTo(T other)
3, 对集合进行排序
a) Collections.sort(List)
Comparator:接口 外比较器
使用:

  1. 一个类实现此接口
  2. 重写compare(T o1,T o2)
  3. 对集合进行排序
    a) Collections.sort(List,Comparator)

如何对集合进行降序排列:
可以的,在表达式前+ -

2.2 队列和栈
LinkedList,此类实现了Deque接口,Deque接口又继承了Queue
Queue:
java.util.Queue:接口
* 队列,可以存储一组元素,但是存取元素必须
* 遵循先进先出原则(FIFO,First Input First Output)

   队列(Queue)是常用的数据结构,可以将队列看成特殊的线性表,队列限制了对线性表的访问方式:
   只能从线性表的一端添加(offer)元素,从另一端取出(poll)元素。
   队列遵循先进先出(FIFO First Input First Output )的原则。
   JDK中提供了Queue接口,同时使得LinkedList实现了该接口

(LinkedList实现Queue的原因在于Queue经常要进行添加和删除的操作,而LinkedList在这方面效率较高)。

Queue方法:
Offer(E e):将一个对象添加至队尾,如果添加成功则返回true。
poll(): 从队首删除并返回一个元素–string
peek():返回队首的元素(但并不删除)。–string

/**

  • Queue:队列是一种数据结构,特点先进先出
  • 只能从一端添加元素,从另一端取出元素
  • @author adminitartor

*/

public class Demo01 {
  
   public static void main(String[] args) {
      Queue<String> queue = new LinkedList<String>();
      queue.offer("x");
      queue.offer("b");
      queue.offer("c");
     
      String str = queue.poll();
      System.out.println(str);
     
      String str1 = queue.peek();
      System.out.println(str1);
     
      System.out.println(queue);
     
     
   }
 
Queue的遍历
 
   /*
       * 队列的遍历
       * foreach
       */
      for(String s:queue){
         System.out.println(s);
      }
     
      /*
       * 队列自行遍历
       */
      while(queue.size()>0){
         String str =queue.poll();
         System.out.println(str);
      }

Deque:
Deque是接口,继承了Queue接口

• Deque是Queue的子接口,定义了所谓“双端队列”即从队列的两端分别可以入队(offer)和出队(poll),LinkedList实现了该接口。
• Deque:数据结构,双端队列
• 特点:可以从队列的两端分别入队和出队
Deque方法:
Offer(E e)
offerFirst(E e)
offerLast(E e)
poll()
pollFirst()
pollLast()

/**

  • Deque是接口,继承了Queue接口
  • 叫做双端队列
  • 特点:可以从两端分别入队和出队
  • @author adminitartor

*/

public class DequeDemo {
  
   public static void main(String[] args) {
      //创建Deque
      Deque<String> deque =
            new LinkedList<String>();
      //向此队列中插入2个元素 - offer(E)
      deque.offer("java");
      deque.offer("c++");
     
      System.out.println(deque);
     
      //在队首插入元素
      deque.offerFirst("php");
      System.out.println(deque);
     
      //在队尾插入元素
      deque.offerLast("last");
      System.out.println(deque);
     
     
      //获取队列的队首的第一个元素并移除
      String str = deque.poll();
      System.out.println(str);
      System.out.println(deque);
     
      //获取并移除队尾的元素
      String last = deque.pollLast();
      System.out.println(last);
      System.out.println(deque);
     
     
     
     
   }
 
}
 

Stack:
先进后出
• 如果将Deque限制为只能从一端入队和出队,则可实现“栈”(Stack)的数据结构,对于栈而言,入栈称之为push,出栈称之为pop。
• 栈遵循先进后出(FILO First Input Last Output )的原则。

Stack方法
栈中的两个方法:
push(E) :将元素压入栈顶
pop():从栈顶取出元素,并从栈中移除

/**

  • 如果对Deque进行限制,只允许从一端进行
  • 入队和出队,此时就形成了Stack数据结构
  • 特点:先进后出

*/

public class StackDemo {
   public static void main(String[] args) {
      //创建一个集合对象存放数据
      Deque<String> stack =
            new LinkedList<String>();
      stack.push("a");
      stack.push("s");
      stack.push("x");
     
      System.out.println(stack);
     
      String str = stack.pop();
      System.out.println(str);
      System.out.println(stack);
   }
  1. Set接口

Set集合:不可重复集
Collection接口:
List集合:是可重复集,有序的
Set集合:不可重复集
HashSet():无序的

元素不可重复
添加元素时,调用集合中元素的equals方法

实现类:HashSet()
 
Student类
Set<Student> set = new HashSet<Student>();
Student stu = new Student(1001,”aa”);
Student stu1 = new Student(1001,”aa”);
set.add(stu)    true
set.add(stu1)  
如果Student类中没重写equals,返回true
    如果重写了equlas,返回false
 
/**
 * List集合是可重复集
 * Set集合是不可重复集
 * @author adminitartor
 *
 */
public class Demo01 {
  
   public static void main(String[] args) {
//    List<String> list =
//          new ArrayList<String>();
//   
//    list.add("a");
//    list.add("b");
//    list.add("a");
//   
//    System.out.println(list);
     
      /*
       * set接口的实现类:HashSet()
       */
      Set<String> set =
            new HashSet<String>();
      boolean flag = set.add("a");
      set.add("b");
      set.add("c");
     
//    System.out.println(set);
     
//    set.remove("a");
//    System.out.println(set);
//    boolean flag1 = set.add("a");
//    System.out.println(flag);
//    System.out.println(flag1);
     
     
      /*
       * set集合的遍历
       * iterator
       * foreach
       */
      for(String s:set){
         System.out.println(s);
      }
     
     
   }
   

4 查找表:map<k,v>
4.1Map接口
• 保存具有映射关系的数据 – Map集合

语文 - 90
数学 – 80
英语 – 20

key – value 键值对

key是唯一的 通过key来找元素的

     Map<Key,Value>
        Key,Value必须都是引用类型

• Map接口定义的集合又称查找表,用于存储所谓“Key-Value”映射对。Key可以看成是Value的索引,作为Key的对象在集合中不可以重复。
• 根据内部数据结构的不同,Map接口有多种实现类,其中常用的有内部为hash表实现的HashMap和内部为排序红黑树实现的TreeMap。

Map接口中定义的方法:
put(K key,V value):
向集合中存放元素。
如果存放的key值已经存在,会怎么样?
覆盖掉此key原来的value值

/**

  • Map集合保存的是一组一组的键值对(具有映射关系的数据)
  • 实现:
  • HashMap()\
  • 对象的创建,添加元素的方法
  • @author adminitartor

*/

public class MapDemo01 {
  
   public static void main(String[] args) {
      //创建一个Map集合对象
      Map<String, Integer> map =
            new HashMap<String,Integer>();
     
      //向集合中添加元素 - put(K,V)
      /*
       * put(K,V) - V - 将此Key原来对应的Value返回
       * 如果此Key之前不存在,那么返回null
       */
      map.put("语文",90);
      Integer math = map.put("数学", 80);
      map.put("英语", 90);
      map.put("语文", 70);
      System.out.println(math);
      System.out.println(map);
     
   }
}
 
  get(K key) – V
 
 
  containsKey(Object key):判读某个key是否在Map中存在
/*
       * 根据key值取出对应的value值
       * get(K key) - V
       */
      int a = map.get("语文");
      System.out.println(a);
     
      /*
       * 对某个键值进行判断,判断是否已经存在于集合中
       * containsKey(K key) - boolean
       */
      boolean flag = map.containsKey("语文");
      System.out.println(flag);

练习:
Student放入map集合,通过学号来找学生对象

key – Integer
value – Student

4.2实现类 HashMap
HashCode()
Object类中的hashCode()方法:返回该对象所在内存地址的整数形式

hashCode()的稳定性:
同一个对象在一个程序中,多次调用hashCode()生成的整数一定是相同的

如果两个对象equals相等,那么得到的hashCode值(返回的是一个int值)一定相等,
但是如果两个对象的hashCode值相等,这两个对象不一定equals – 即hashCode值不是唯一的

Hash算法:
key的hashCode值 经过散列算法,得到散列下标,不同的hashcode值经过散列算法得到的散列下标可能相同,如果散列下标相同,那么出现链表

HashMap:查找性能是最高的。 - 由数据结构决定的

   出现链表会降低查询性能,HashMap的查询性能是最好的。

为了降低链表出现的概率,需重写equals和hashcode方法,重写这两个方法可以降低链表出现概率,但不能避免

HashMap:
HashMap内部由数组实现,是当今查询速度最快的数据结构.
* HashMap根据key元素决定这组键值对应当存放在
* 数组的位置,并且也是根据key元素得到位置来检索
* 数组中的该组键值对以此省去了遍历数组的过程.
*
* 但是使用HashMap时应当尽量避免出现链表的情况.
* HashMap中链表的产生原因:
* HashMap是根据key元素的hashcode方法返回的数字
* 经过散列计算得到该组键值对应当存放在数组的哪个
* 位置,而根据key元素equals比较查看当前key是否
* 已经存在于Map中,若存在则直接替换该位置这个key
* 所对应的value,但是若数组该位置已经存在键值对,
* 并且key与当前准备存放的键值对中的key的equals
* 比较不同时,则会在数组当前位置产生链表.这样在
* 将来根据key检索时会出现遍历链表的情况,这样就
* 会降低HashMap查询性能.
* 总结:当key元素hashcode值相同,但是equals比较不同
* 时就会在HashMap中产生链表,影响查询性能.

如何尽可能的避免出现链表?
   重写hashCode和equals方法

4.3 Map的遍历
KeySet():
得到一个key值的set集合
entrySet(): - Set<Entry<K,V>>
得到map集合中的所有键值对的set集合Map的遍历:
keySet() – key的set集合
entrySet() – Set<Entry<K,V>>
得到map集合中所有键值对的set集合
注意点:对此集合进行遍历,注意每个元素的类型是Entry<K,V>

案例
Map<String, Integer> map =
new HashMap<String, Integer>();

	map.put("语文", 90);
	map.put("数学", 90);
	map.put("英语",90);
	//获取到所有key值 - set集合
	Set<String> keyset = map.keySet();
	//遍历set集合
	for(String s:keyset){
		System.out.println(s);
	}//输出的结果跟自己添加的顺序不一样,也就是无序的,内层根据字母顺序排序
	/*
	 * entrySet():
	 * 	得到map集合中所有元素的set集合
	 */
	Set<Entry<String, Integer>> set = 
			map.entrySet();
	
	//对set集合进行遍历
	for(Entry<String, Integer> e:set){
		String key = e.getKey();
		Integer it = e.getValue();
		System.out.println(key +" - "+it);
   取键值和value值
       getKey()
       getValue()

Map:接口,保存是键值对 key –value对
put(K,V)
get(K) – V
containsKey(K)-boolean
案例:


Map<String, Integer> map = new HashMap<String,Integer>();		
		//向集合中添加元素 - put(K,V)
		/*
		 * put(K,V) - V - 将此Key原来对应的Value返回
		 * 如果此Key之前不存在,那么返回null
		 */
		map.put("语文",90);
		Integer math = map.put("数学", 80);
		map.put("英语", 90);
		map.put("语文", 70);
		System.out.println(math);
		System.out.println(map);
		
		/*
		 * 根据key值取出对应的value值
		 * get(K key) - V
		 */
		int a = map.get("语文");get得到value返回key
		System.out.println(a);
		
		/*
		 * 对某个键值进行判断,判断是否已经存在于集合中
		 * containsKey(K key) - boolean
		 */
		boolean flag = map.containsKey("语文");
		System.out.println(flag);

实现类:
HashMap:数据结构,是查询性能最高的数据结构

为了尽可能的避免出现链表,重写equals和hashCode()

Map对象的创建
向map集合中放元素
取元素

4.4 有序的Map-- LinkedHashMap
• 使用Map接口的哈希表和链表实现,具有可预知的迭代顺序。此实现与 HashMap 的不同之处在于:
LinkedHashMap维护着一个双向循环链表。此链表定义了迭代顺序,该迭代顺序通常就是存放元素的顺序。

案例:
   HashMap中元素取出顺序和Put的顺序不一定一样
   LinkedHashMap中元素取出顺序和put的顺序一致 

练习:
1.在控制台输入n个学生的信息,存放到List中。
学生信息包括:姓名(String),学号(int),分数(double)

2.一个集合存放的是商品对象,将此集合看成是购物车,
现将购物车中数量为0的商品移除掉 - iterator
public class HomeWork1 {
public static void main(String[] args) {
//创建一个集合当成购物车
List list = new ArrayList();

	//创建商品对象
	Good phone = new Good("iphonex", 1, 2);
	Good tv = new Good("TV", 2, 1);
	Good pc = new Good("PC", 3, 3);		
	pc.setCount(0);		
	//加入集合
	list.add(phone);
	list.add(tv);
	list.add(pc);
	System.out.println(list);	
	//对购物车中的商品进行检查,移除数量为0的商品
	Iterator<Good> it = list.iterator();
	while(it.hasNext()){
		Good good = it.next();
		//对数量进行判断
		if(good.getCount()==0){
			it.remove();
		}
	}
	System.out.println(list);

public class Good {
private String name;
private int id;
private int count;
public Good() {
super();
// TODO Auto-generated constructor stub
}
public Good(String name, int id, int count) {
super();
this.name = name;
this.id = id;
this.count = count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
@Override
public String toString() {
return “Good [name=” + name + “, id=” + id + “, count=” + count + “]”;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Good other = (Good) obj;
if (id != other.id)
return false;
return true;
}
3.判断指定学号的学生是否已经录入学校网站(集合表示 contains
//定义一个集合
List list =
new ArrayList();

	Student student = new Student(1001, "aa");
	
	list.add(student);
	
	Student student2 = new Student(1001, "aa");
	
	//对此学生是否已经存在进行判断
	boolean flag = list.contains(student2);
	
	if(!flag){
		list.add(student2);
	}
	
	System.out.println(list);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值