Java教程

Java基础知识复习3--集合Map篇

本文主要是介绍Java基础知识复习3--集合Map篇,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

以下内容均来自于B站“动力节点之老杜java基础教程”

集合

集合既容器(也是一个对象),一次可以容纳多个对象。集合中任何时候存储的都是“引用”!

java中不同的集合对应的数据结构是不一样的!如:数组,链表,二叉树,哈希表。。。

集合继承结构图:

Map

注意,map和collection是没有继承关系的,两者是相对独立的!

总结

以上图必须牢记!!!!


Collection

在使用了泛型之后,Collection中只能存储某个具体了类型!没有使用泛型之前,可以存储Object的所有子类型!集合中不能直接存储基本数据类型,也不能存java对象,只能存储java对象的内存地址

import java.util.ArrayList;
import java.util.Collection;
public class CellectionTest01 {
    public static void main(String[] args) {
        //多态,父类型的引用,指向了子类型的对象!Collection只是一个集合类接口!
        Collection c=new ArrayList();
        c.add(10);//自动装箱!实际上是放了一个对象的内存地址
        c.add(3.14);
        c.add(new Object());
        c.add(true);
    }
}

常用方法

迭代器(*********)

接口Collection继承了接口Iterable,从而也就继承了iterator()方法,当Collection调用该方法时,返回一个迭代器Iterator,目的就是迭代集合(遍历集合)!该迭代器适用于所有的集合(Map除外)!

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class CellctionTest02 {
    public static void main(String[] args) {
        Collection c=new HashSet();
        c.add("abc");c.add("def");c.add(100);c.add(new Object());
        //使用迭代器
        Iterator it=c.iterator();
        //遍历
        //迭代器判断指向的下一位元素是否还存在!boolean hasNext();
        while(it.hasNext()){
            //让迭代器前进一位,并将指向的元素拿到!Object next();
            Object obj=it.next();
            System.out.println(obj);
        }
    }
}

ArrayList和HashSet初识

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CellectionTset03 {
    public static void main(String[] args) {
        //ArrayList特点:有序可重复(添加的顺序)
        Collection c=new ArrayList();
        c.add(1);c.add(2);c.add(3);c.add(4);c.add(2);
        //遍历
        Iterator it=c.iterator();
        while(it.hasNext()){
            Object ob=it.next();//让迭代器前进一位,并将指向的元素拿到!Object next();
            System.out.println(ob);
        }
    }
}

你存进去是什么类型,取出来还是什么类型,只是在sout的时候给你转化为字符串(调用toString方法)

import java.util.HashSet;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest04 {
    public static void main(String[] args) {
        //HashSet特点:无序不可重复(添加的顺序)
        Collection c=new HashSet();
        c.add(1);c.add(3);c.add(4);c.add(2);c.add(2);c.add(-5);c.add(9);c.add(7);
        //遍历
        Iterator it=c.iterator();
        while(it.hasNext()){
            Object ob=it.next();
            System.out.println(ob);
        }
    }
}

深入Collection集合的contains方法

import java.util.ArrayList;
import java.util.Collection;
public class CollectionTest05 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        String s1="abc";
        String s2="def";
        c.add(s2);c.add(s1);
        String x=new String("abc");
        System.out.println(c.contains(x));
    }
}

可能与我们想的不一样!因为s1和x两个对象虽然内容一样,但是对象地址不一样!

我们可以看到集合c不包含x,事实上也确实没有把x添加进去,那么为什么结果运行还是true呢,这个得看contains方法的底层源代码是怎么比的(既看是否有equals方法),通过查看底层源代码,发现使用o.equals(es[i])方法,与上对比其中x是o,es[i]是s1,既x.equals(s1)------->true?回答是true,因为String类中重写了equals方法,对比的是内容而不再是对象地址了

测试2

import java.util.ArrayList;
import java.util.Collection;
public class CollectionTest06 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        Student s1=new Student("jack");
        Student s2=new Student("jack");
        c.add(s1);
        System.out.println(c.contains(s2));
    }
}
class Student{
    private String name;
    Student(){}
    Student(String name){
        this.name=name;
    }
}

那为什么这个又是false呢?通过上面我们知道,contains的底层是通过调用equals方法来判断,又因为Student类没有重写,从而比较的是内存地址(s1.equals(s2)),当然是false了!

所以,我们重写Student中的equals方法,就能是运行结果为true了

 //重写我们自己需要的equals方法,比较原理为内容相同
 @Override
 public boolean equals(Object o) {
     if(o==null||!(o instanceof Student))
         return false;
     if(o==this)
         return true;
     Student s=(Student)o;
     return s.name.equals(this.name);
 }

总结:放在集合中的元素,需要重写equals方法,不重写比较的对象的内存地址,重写了比较的是内容!

remove

直接说结果,都不用敲代码演示了,remove方法的底层也是需要通过调用equals方法来比较的,所以你不重写equals方法,则比较的就是Object对象(既对象的内存地址),重写了就是另外一回事了!

迭代器之remove

先看一段代码:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest07 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        c.add("abc");
        c.add("def");
        c.add("ghi");
        //通过迭代器,拿到一个元素删除一个元素
        Iterator it=c.iterator();
        while(it.hasNext()){
            Object o=it.next();
            c.remove(o);//删除拿到的元素在集合中
            System.out.println(o);
        }
    }
}

然后我们会发现报错,这是为什么呢?因为java规定,一旦集合的结构发生了改变,必须重新获取迭代器,否则便会出现异常!上面删除了元素,没有重新获取迭代器而是直接在原迭代器上直接操作,然后出现了异常!

怎么解决这种问题呢?使用迭代器自己的删除方法remove!

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest07 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        c.add("abc");
        c.add("def");
        c.add("ghi");
        Iterator it=c.iterator();
        while(it.hasNext()){
            Object o=it.next();
            //最大的区别
            it.remove();//删除的一定是迭代器自己的元素
            System.out.println(o);
        }
    }
}

第一个出错的原因是:集合中的元素删了,但是没有更新迭代器;第二个可以是因为通过迭代器去删除时,会自动更新迭代器,并且更新集合(既删除集合中的元素)!


List

List是Collection接口的子接口,特点是有序(有下标)可重复,我们着重学习List特有的方法

其中E代表泛型(后面会讲解),分别是向指定的索引下标(从0开始)添加元素、根据索引下标获取对应的元素、根据元素获取对应的索引下标(第一次出现)、获取指定元素最后一次出现处的索引、根据索引下标删除对应的元素、根据索引下标重新设置其对应的元素!

注意,要想使用以上方法,通过面向对象篇(多态)来熟悉以下两种方式的区别:

List list=new ArrayList<>();//可以
Collection c=new ArrayList<>();//不可以,无法使用List特有的方法,只能使用原Collection自有的方法

方法举例

import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
public class ListTest01 {
    public static void main(String[] args) {
        List list=new ArrayList<>();
        //对于ArrayList来说,add是在末尾添加
        list.add("a");list.add("b");list.add("c");
        Iterator it=list.iterator();
        while(it.hasNext()){
            Object o=it.next();
            System.out.println(o);
        }
        System.out.println("====================");
        list.add(1,"d");//一般不推荐,效率比较低,参考数据结构链表中元素的插入!
        //通过for循环来遍历
        for (int i = 0; i <list.size() ; i++) {
            Object o=list.get(i);
            System.out.println(o);
        }
    }
}

ps:


ArrayList

ArrayList的另一种构造方法

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
public class test1 {
    public static void main(String[] args) {
        Collection c=new HashSet();
        c.add(100);c.add(500);c.add(400);c.add(200);
        //通过这种构造方法,可以将HashSet集合转换为list集合
        List list=new ArrayList(c);
        for (int i = 0; i <list.size() ; i++) {
            System.out.println(list.get(i));
        }
    }
}

注意,ArrayList是非线程安全的集合!!


LinkedList

单链表

在接触java自带的LinkedList之前,需要学习一下链表(单链表)这种数据结构

链表优点:随机增删元素效率较高(因为增删元素不涉及到大量的元素位移)

​ 既在以后开发中遇到随机增删业务比较多建议用链表

链表缺点:查询效率低,每次查得从头节点开始往下遍历!

我们自己写一个单链表,来加深对其的理解(本质就是自己写数据结构):

/*
单链表中的节点
节点为单链表中的基本单元,包含"数据"和"下一个节点的内存地址"这两个属性
*/
public class Node {
    Object element;
    Node next;
    public Node(){};
    public Node(Object element,Node next){
        this.element=element;
        this.next=next;
    }
}
public class Link {
    Node header;
    int size=0;
    public int getSize(){
        return size;
    }
    public void add(Object data){//增
        if(header==null){ //假如没有头节点,则添加的这个既作为头节点
            header=new Node(data,null);
        }else{//假如有头节点,找到最后一个节点,添加至其后
            Node currentLastNode=findLast(header);
            currentLastNode.next=new Node(data,null);
        }
        size++;
    }
    //通过递归调用,创建一个寻找到链表尾节点的方法
    public static Node findLast(Node node){
        if(node.next==null){
            return node;
        }else{
            return findLast(node.next);
        }
    }
    public void remove(Object obj){//删
    }
    public void modify(Object obj){//改
    }
    public void find(Object obj){//查
    }
}

public class Test01 {
    public static void main(String[] args) {
        Link link=new Link();
        link.add(100);
        link.add(200);
        link.add(300);
        System.out.println(link.getSize());
    }
}

需要注意的是,不是因为ArrayList有下标(linkedList也有下标)才检索快,而是因为ArrayList底层是数组,数组存放元素的地址是连续的,这才是ArrayList检索快的原因!而LinkedList即使有下标,也必须从头结点开始遍历一个一个的找!

双链表(LinkedList)


Vector

那么,我们怎么将一个线程不安全的集合ArrayList转换成线程安全的集合呢?

import java.util.ArrayList;
import java.util.List;
//1,先导包(工具类)
import java.util.Collections;
public class Test01 {
    public static void main(String[] args) {
        List myList=new ArrayList();//非线程安全

        //2,变成线程安全的(目前无法测试,强记)
        Collections.synchronizedList(myList);
        //下面的就是线程安全的了
        myList.add(111);
        myList.add(222);
        myList.add(333);
    }
}

泛型(Genericity)

泛型简介

不使用泛型:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test01 {
    public static void main(String[] args) {
        List myList=new ArrayList();
        Dog b=new Dog();
        Cat c=new Cat();
        myList.add(b);myList.add(c);
        //遍历集合
        Iterator it=myList.iterator();
        while(it.hasNext()){
            //不用泛型,迭代器取出的就只能是Object类
            Object o=it.next();
            //Animal a=it.next(); 编译无法通过
            if(o instanceof Animals){
                //Object中没有move方法,需要向下转型(强转,既高转低)
                Animals a=(Animals)o;
                a.move();
            }
        }
    }
}
class Animals{
    public void move(){
        System.out.println("移动");
    }
}
class Dog extends Animals{}
class Cat extends Animals{}

使用泛型:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Test02 {
    public static void main(String[] args) {
        //使用泛型List<Animals>后,表示myList集合中只允许存储Animals类型
        //用泛型类指定集合中存储的集合类型
        List<Animals> myList=new ArrayList<Animals>();
        Dog b=new Dog();
        Cat c=new Cat();
        myList.add(b);myList.add(c);
        //遍历集合
        Iterator<Animals> it=myList.iterator();
        while(it.hasNext()){
            //使用泛型之后,每次迭代返回的都是Animals类型
            Animals a=it.next();
            a.move();
        }
    }
}
class Animals{
    public void move(){
        System.out.println("移动");
    }
}
class Dog extends Animals {}
class Cat extends Animals {}

泛型的好处:统一了类型;从集合中取出的元素是泛型指定的类型,因此无需进行大量的“向下转型”了

泛型的缺点:集合中的元素缺乏多样性(事实上大多数情况下,集合中的元素类型都是统一的)

钻石表达式:

//ArrayList的<>中无需输入数据类型,系统自动推敲
List<Animals> myList=new ArrayList<>();

自定义泛型

public class Test03<T>{
    public void doSome(T t){
        System.out.println(t);
    }
    public static void main(String[] args) {
        Test03<String> test=new Test03();
        test.doSome("abc");//只能是String类型
    }
}

foreach

又叫增强for循环

import java.util.ArrayList;
import java.util.List;
public class Test04{
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        list.add("abc");
        list.add("def");
        list.add("hij");
        //使用foreach遍历集合 代码简介了很多  可以说增强for就是为泛型集合而生的
        //当前缺点是没有下标,使用foreach时要慎重考虑这点
        for (String s:list) {
            System.out.println(s);
        }
    }
}


Set

在上面最开始我们已经测试了,Set的特点是无序不可重复,不过需要注意的是:

放到HashSet中的元素,实际上是放到了HashMap集合的Key部分!

TreeSet虽然是无序不可重复,但是存储的元素可以按照大小自动排序,称为可排序集合

import java.util.Set;
import java.util.TreeSet;
//Set是无序不可重复的,无序是指没有下标,存放和取出的顺序是不一样的!
public class TreeSet01 {
    public static void main(String[] args) {
        Set<String> strs=new TreeSet<>();
        strs.add("A");
        strs.add("B");
        strs.add("Z");
        strs.add("Y");
        strs.add("Z");
        strs.add("K");
        strs.add("M");
        //遍历
        for (String str:strs) {
            System.out.println(str);
        }
    }
}


Map

Map基础

常用方法:

import java.util.HashSet;
import java.util.Set;
public class Myclass {
    //声明一个静态内部类
    public static class InnerClass{
        public static void m1(){
            System.out.println("静态内部类的m1方法执行");
        }
        public void m2(){
            System.out.println("静态内部类的实例方法m2执行");
        }
    }
    public static void main(String[] args) {
        Myclass.InnerClass.m1();
        //创建静态内部类对象
        Myclass.InnerClass mi=new Myclass.InnerClass();
        mi.m2();
        //泛型(静态内部类)
        Set<Myclass.InnerClass> set=new HashSet<>();
        Set<String> set2=new HashSet<>();
        Set<MyMap.MyEntry<Integer,String>> set3=new HashSet<>();

    }
}
class MyMap{
    //使用泛型的静态内部类
    public static class MyEntry<K,V>{

    }
}

Map的常用方法

public class MapTest01 {
    public static void main(String[] args) {
        Map<Integer,String> map=new HashMap<>();
        map.put(1,"zhangsan");
        map.put(2,"lisi");
        map.put(3,"wamgwu");
        map.put(4,"zhaoliu");
        //通过key获取value
        String value=map.get(2);
        System.out.println(value);
        //获取键值对的数量
        System.out.println("键值对的数量:"+map.size());
        //通过key删除key-value
        map.remove(2);
        System.out.println("键值对的数量:"+map.size());

        //注意,containsKey和containsValue底层都是用非equals进行比较的,需要重新equals方法!
        //判断是否包含某个key
        System.out.println("是否包含key=4:"+map.containsKey(4));
        //判断是否包含某个value
        System.out.println("是否包含value=lishi:"+map.containsValue("lisi"));

        //获取所有的values
        Collection<String> str=map.values();
        for (String s:str) {
            System.out.println(s);
        }
        //清空
        map.clear();
        System.out.println("Map是否为空:"+map.isEmpty());
    }
}

Map的遍历

遍历方式一
//遍历方式1,通过获取所有的key值来遍历
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapTest02 {
    public static void main(String[] args) {
        Map<Integer,String> map=new HashMap<>();
        map.put(1,"zhangsan");
        map.put(2,"lisi");
        map.put(3,"wamgwu");
        map.put(4,"zhaoliu");
        Set<Integer> set =map.keySet();
        for (Integer i:set) {
            System.out.println("key="+i+",values="+map.get(i));
        }
    }
}

遍历方式二

/*
* 第二种遍历方式:Set<Map.Entry<k,v>> entrySet
* 这个是将Map集合全部转换成Set集合
* Set集合中元素的类型是:Map.Entry
* */
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapTest03 {
    public static void main(String[] args) {
        Map<Integer,String> map=new HashMap<>();
        map.put(1,"zhangsan");
        map.put(2,"lisi");
        map.put(3,"wamgwu");
        map.put(4,"zhaoliu");

        Set<Map.Entry<Integer,String>> set=map.entrySet();
        //遍历集合,每次取出一个node
        Iterator<Map.Entry<Integer,String>> it2=set.iterator();
        while (it2.hasNext()){
            //Set的类型就是Map.Entry<Integer,String>
            Map.Entry<Integer,String> node= it2.next();
            Integer key=node.getKey();
            String values= node.getValue();
            System.out.println(key+"="+values);
        }
        /*使用foreach遍历
        for (Map.Entry<Integer,String> node:set) {
            System.out.println(node.getKey()+"="+node.getValue());
        }
        */
    }
}


HashMap

Hash表

下面只是图解,具体想了解可以去数据结构里学习!

重写hashCode和equals

测试一
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapTest01 {
    public static void main(String[] args) {
        //Integer是key,他的hashCode和equals都重写了
        Map<Integer,String> map=new HashMap<>();
        map.put(1111,"zhangsan");
        map.put(6666,"lisi");
        map.put(7777,"wangwu");
        map.put(2222,"zhaoliu");
        map.put(2222,"king");
        System.out.println(map.size());//4,key重复的时候,value自动覆盖
        Set<Map.Entry<Integer,String>> set= map.entrySet();
        for (Map.Entry<Integer,String> node:set) {
            System.out.println(node.getKey()+"="+node.getValue());
        }
    }
}

HashMap的默认初始化时16,加载因子为0.75(底层数组的容量达到75%就开始扩容)

HashMap的初始化容量必须为2的倍数,这也是官方推荐的!

测试二
public class Student {
    private String name;
    public Student() {}
    public Student(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    //hashCode 
    //equals 如果学生名字一样,表示同一个学生
    public boolean equals(Object obj){
        if(obj==null||!(obj instanceof Student))
            return false;
        if(obj==this)
            return true;
        Student s=(Student)obj;
        return s.getName().equals(this.name);
    }
}
import java.util.HashSet;
import java.util.Set;
public class HashMapTest02 {
    public static void main(String[] args) {
        Student s1=new Student("zhangsan");
        Student s2=new Student("zhangsan");
        //重写equal方法之后是true
        System.out.println(s1.equals(s2));
        System.out.println("s1的hashCode:"+s1.hashCode());
        System.out.println("s2的hashCode:"+s2.hashCode());
        //由于上面的equals返回的是true,我们往hashSet集合中放,按理说只能放一个(HashSet:无序不可重复)
        Set<Student> set=new HashSet<>();
        set.add(s1);
        set.add(s2);
        System.out.println(set.size());
    }
}

PS:向Map集合中存与取,都是先调用key的hashCode方法,再调用equals方法,equals有可能调用有可能不调用!

也就是说,向上面这样,数组下标为5的位置上为null既没有元素,则不会执行equals,直接插入就行了,否则像134这种都会执行equals方法来进行比较从而进行插入还是覆盖!

所以,上面测试二的执行结果是set.size()=2(原因上面也分析了,因为先执行hashCode,不同则插入)不符合HashSet集合的存储特点,

所以一个类的equals方法如果重写的话,也要同时且必须重写hashCode方法,既equals返回true,则hashCode方法的返回值必须一样!

好在这块儿不需要你自己去重写,直接通过IDEA自己的重写方法自动给你完成了!

你再运行测试二的代码:

终极结论:放在HashMap集合key部分的,以及放在HashSet集合中的元素,需要同时重写hashcode方法和equals方法!

JDK8后的HashMap

最后再说一下,同一个链表上的Hash值可能不一样,因为有可能碰撞了,但转换的数组下标是一样的,这个其实也不要紧,因为会往链表下面添加;假如两个的hash值是一样的,肯定在同一链表上!


HashTable

所谓只有一个是因为put方法如果有key值则会覆盖原value值

Properties

import java.util.Properties;
public class PropertiesTest01 {
    public static void main(String[] args) {
        //创建一个Properties对象
        Properties pro=new Properties();
        //需要掌握的两个方法:一个存,一个取
        pro.setProperty("101","zhangsan");
        pro.setProperty("102","lisi");
        pro.setProperty("103","wangwu");
        pro.setProperty("104","zhaoliu");
        //通过key值获取value
        String s1=pro.getProperty("101");
        String s2=pro.getProperty("102");
        String s3=pro.getProperty("103");
        String s4=pro.getProperty("104");
        //输出
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
        System.out.println(s4);
    }
}

PS:建议把各个集合的初始容量和扩容倍数牢记(背),面试容易问!


TreeMap

public class TreaSetTest01 {
    public static void main(String[] args) {
        TreeSet<String> ts=new TreeSet<>();
        ts.add("zhangsan");
        ts.add("lisi");
        ts.add("wnagwu");
        ts.add("zhangsi");
        for (String s:ts) {
            System.out.println(s);
        }
    }
}

第一种排序

字符和数字是可以排序的,那么我们自定义的类型怎么办呢?这就需要该类型继承java.lang.Comparable接口,并且实现compareTo方法!

import java.util.TreeSet;
public class TreeSetTest03 {
    public static void main(String[] args) {
        Customer c1=new Customer(32);
        Customer c2=new Customer(20);
        Customer c3=new Customer(30);
        Customer c4=new Customer(25);
        TreeSet<Customer> customer=new TreeSet<>();
        customer.add(c1);
        customer.add(c2);
        customer.add(c3);
        customer.add(c4);
        for (Customer c:customer) {
            System.out.println(c);
        }
    }
}

//放在TreeSet集合中的元素需要继承java.lang.Comparable接口
//并且实现compareTo方法,equals可以不写
class Customer implements Comparable<Customer>{
    int age;
    public Customer(int age) {
        this.age = age;
    }
    //编写比较的逻辑
    @Override
    public int compareTo(Customer o) {
        int age1=this.age;
        int age2=o.age;
        if(age1==age2){
            return 0;
        }else if(age1>age2){
            return 1;
        }else {
            return -1;
        }
    }
    //重写toString
    @Override  
    public String toString() {
        return "Customer[age="+this.age+"}";
    }
}

通过上面操作,成功达成了我们自定义类型的排序!像前面的Integer和String都能排是因为都实现了Comparable接口的方法,只不过是java帮我们自动实现了!

比较的规则底层利用了二叉树(感兴趣的可以自己查阅数据结构)

第二种排序

单独编写比较器

import java.util.Comparator;
import java.util.TreeSet;
//TreeSet的可排序的第二种方法,使用比较器
public class TreeSetTest06 {
    public static void main(String[] args) {
        //创建TreeSet集合的时候,需要使用这个比较器
        //注意新的构造方法
        TreeSet<Wugui>  wuguis=new TreeSet<>(new WuguiComparator());
        wuguis.add(new Wugui(100));
        wuguis.add(new Wugui(800));
        wuguis.add(new Wugui(300));
        //遍历
        for (Wugui w:wuguis) {
            System.out.println(w);
        }
    }
}
class Wugui{
    int age;
    public Wugui(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "wugui{" + "age=" + age + '}';
    }
}
//单独在这里编写一个比较器
//比较器实现java.util.Comparator接口(Comparable是java.lang包下的)
class WuguiComparator implements Comparator<Wugui>{
    //重写比较规则
    @Override
    public int compare(Wugui o1,  Wugui o2) {
        return o1.age-o2.age;
    }
}

或者,为了简便,使用匿名内部类的方式!注意,这个类没有名字,后面直接new接口

TreeSet<Wugui>  wuguis=new TreeSet<>(new WuguiComparator(){
   //重写比较规则
    @Override
    public int compare(Wugui o1,  Wugui o2) {
        return o1.age-o2.age;
    }
});

那么这两种方式怎么选择呢?


Collections工具类

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TreeSetTest07 {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        //变成线程安全的
        Collections.synchronizedList(list);
        //排序
        list.add("abf");
        list.add("abc");
        list.add("abb");
        list.add("abx");
        //里面只能是list集合,且集合中的类型必须实现Comparable接口
        //如果是Set集合,可以转换为List再使用Collections工具排序
        Collections.sort(list);
        for(String s:list){
            System.out.println(s);
        }
    }
}

这篇关于Java基础知识复习3--集合Map篇的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!