(2020年7月22日13:09:31)集合笔记{2020年7月29日22:07:13}

认识集合

  • 集合都在JDK中java.util包下;
  • 集合分为两大类
    • 单个方式存储元素(超级父接口:java.util.Collection;)
    • 键值对的方式存储元素(超级父接口:java.util.Map;)
  • 集合是一种存放对引用(内存地址)的容器,集合中不能直接存储对象与基本类型
  • 每一种集合对应着不同的数据结构,不同给的数据结构,采用的存储方式不同。
  • 集合常用接口结构图在这里插入图片描述

1、创建集合对象

//Collection c=new Collection();  接口不能实例化
//多态,父类型引用子类型对象,可以实现子类型对象方法
Collection C = new ArrayList();

2、Collection 接口中常用方法

1.boolean add(Object o);
  • 向集合中添加集合元素:默认
C.add(10_0000_0000);//自动装箱(java5的新特性// ),实际上是放了一个对象的内存地址点对于Integer x=new Integer(10_0000_0000);
C.add(new Object());
C.add(new student());
2.boolean remove(Object o);
  • 删除集合中某一个元素
C.remove();
3.int size();
  • 获取集合中元素的个数。
//size();获取集合中元素的个数。
System.out.println("集合里有"+ C.size()+"元素");
4.boolean contains(Object o);
  • 检测集合是否包含指定元素。有则出true,无则出false。

  • 底层是:引用equals方法,匹配元素。

boolean b=C.contains("李楠");
System.out.println(b);
5.void clear(Object o)
  • 清空集合
  C.clear();
6.boolean isEmpty(Object 0);
  • 判断集合是否为空,true 没有元素,false有元素。
System.out.println("判断集合是否为空");
System.out.println(C.isEmpty());
7.Object[] toArray();
  • 将集合转化为数组
System.out.println("toArray()将集合转换为数组");
//遍历出数组
for (Object a:C.toArray()){
    System.out.println(a);
}

注意:collection接口中 remove、 contains方法都会调用底层equals方法。

  • 无论重不重写equals方法,contains方法都会调用equals,重写了就会调用重写方法,不重写调用Object中的equals方法

  • Object中的equals方法:public boolean equals(Object obj) {return (this == obj); }比较的是内存地址

3、迭代器(Iterator方法)

1.迭代器基本

  • **作用:**迭代(遍历)集合
  • 注意:
    • 集合翻身改变时,重写迭代器。
    • 在Map集合中不能使用,在所有的Collection以及子类中使用。
    • 迭代出的数据只能使用Object接收。(类型还是储存时的类型)
  • 特别注意、注意、注意
    • 当集合结构发生改变的时候(集合增删改),迭代器不会自动刷新,没有重写迭代器时,调用next方法,会报错。
      • 报错:java.util.ConcurrentModificationException
    • 当迭代器对象调用iterator中的remove方法时,会更新迭代器,不会报错。
      • remove();迭代器iterator中的删除元素的方法。
 public static void main(String[] args) {
     //接口无法实例化,可以利用多态:父类引用子类型对象
     Collection c= new ArrayList();//后面的集合无所谓,主要是看前面的Collection接口怎么遍历、迭代
     //给集合c添加元素
     c.add("string");
     c.add("汉字");
     c.add(1000_0000);
     c.add(new Object());
     //获取迭代器对象
     Iterator iterator=c.iterator();
/*
     Iterator接口中的两个方法:
       1.Object next();返回迭代的下一个元素。
       2.boolean hasNext();如果仍还有元素可以迭代,则返回true
*/
     //调用迭代器对象中的方法
     while (iterator.hasNext()){
         //只能用Object类型接收
         Object o=iterator.next();
         System.out.println(o);
     }
 }

2.迭代器的通用性和HashSet的无序不可重复性()

public static void main(String[] args) {
    //创建集合对象
    Collection c= new HashSet();
    //添加元素
    c.add(100);
    c.add(200);
    c.add(300);
    c.add(400);
    c.add(500);
    c.add(600);
    c.add(700);
    c.add(800);
    c.add(900);
    c.add(1000);
    c.add(100);
    //创建迭代器对象
    Iterator it=c.iterator();
    //通过迭代器中方法循环迭代集合
    while(it.hasNext()){
        System.out.println(it.next());
    }/*
        输出结果:400
                800
                100
                500
                900
                200
                600
                1000
                300
                700
    */
}
  • 迭代器基本里面,示例ArrayList()类的使用,这里也示例了在HashSet()中的使用,结果都是可以使用

  • 只输出了一个100。说明元素重复时,没有成功录入

  • 输出和存储时的顺序不一致

3、遍历集合的三种方法

  • 迭代器、for循环、foreger循环(后两者只能在有下标的集合中使用)

  • **切记切记:**使用foreger增强型for循环时直接输出接收变量。

 public static void main(String[] args) {
        ArrayList<String> Str = new ArrayList<>();
        Str.add("string01");
        Str.add("string02");
        Str.add("string03");
     
        //迭代器遍历集合
        System.out.println("迭代器遍历集合");
        Iterator<String> it=Str.iterator();
        while (it.hasNext()){
            String s=it.next();
            System.out.println(s);
        }
     
        //常规for循环遍历(只针对有下标的集合)
        System.out.println("常规for循环遍历");
        for (int i=0;i< Str.size();i++) {
            System.out.println(Str.get(i));
        }
     
        //增强型foreach循环遍历循环(只针对有下标的集合)
        System.out.println("增强型foreach循环遍历循环");
        //因为是集合是String类型所以用string接收元素。
        for (String s:Str){
            System.out.println(s);
        }
     
        //创建integer类型集合
        List<Integer> in=new ArrayList<>();
        //添加元素
        in.add(1);
        in.add(2);
        in.add(3);
        //迭代器遍历集合
        System.out.println("迭代器遍历integer集合");
        Iterator<Integer> ite = in.iterator();
        while (ite.hasNext()){
            int i=ite.next();
            System.out.println(i);
        }
     
        //常规for循环遍历integer集合
        System.out.println("常规for循环遍历integer集合");
        for (int i = 0; i < Str.size() ; i++) {
            System.out.println(in.get(i));
        }
     
        //增强型for循环遍历integer集合
        System.out.println("增强型for循环遍历integer集合");
        for(Integer i:in){
            //注意:增强型foreger循环输出时,直接输出(Integer)i
            System.out.println(i);
        }

4、LIst集合(接口)

1 、list集合示例
  • 特点:

    • 有序:集合元素有下标,从0开始,以1递增。
    • 可重复:储存相同的元素(两个“1”)
  • List特有方法示例

public static void main(String[] args) {
    //创建List集合对象
    List list=new ArrayList();
    //添加元素
        //默认在末尾添加元素(一般使用)
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("e");
        list.add("aa");
        //在指定位置插入元素:index(下标)element(元素)
        //用的不多,对于ArrayList集合效率比较低。
    System.out.println("在第一位插入:aa");
    list.add(0,"aa");

    //创建迭代器对象
    Iterator it=list.iterator();

    //迭代
    while (it.hasNext()){
        Object o=it.next();
        System.out.print(o + "、");
    }

    System.out.println("根据下标获取第一位集合元素");
    Object ind=list.get(0);
    System.out.println(ind);
    System.out.println();

    System.out.println("根据下标修改元素第二位");
    list.set(1,"A");
    Object obj=list.get(1);
    System.out.println(obj);
    System.out.println();

    System.out.println("输出返回列表中第一次出现的指定元素(aa)索引");
    System.out.println(list.indexOf("aa"));
    System.out.println();

    System.out.println("输出返回列表中最后出现的指定元素(aa)索引");
    System.out.println(list.lastIndexOf("aa"));
    System.out.println();

    System.out.println("移出集合中第一次出现的指定元素");
    System.out.println("移出元素前:");
    Iterator it2= list.iterator();
    while (it2.hasNext()){
        Object o=it2.next();
        System.out.print(o+"、");
    }

    //移除方法
    list.remove("aa");

    System.out.println();
    System.out.println("移出元素后:");
    Iterator it3= list.iterator();
    while (it3.hasNext()){
        Object ob=it3.next();
        System.out.print(ob+"、");
    }

}
  • 输出结果:~~~
 在第一位插入:aa
   aa、a、b、c、d、e、aa、
   根据下标获取第一位集合元素
   aa
 
   根据下标修改元素第二位
   A
 
   输出返回列表中第一次出现的指定元素(aa)索引
   0
 
   输出返回列表中最后出现的指定元素(aa)索引
   6
 
   移出集合中第一次出现的指定元素
   移出元素前:
   aa、A、b、c、d、e、aa、
   移出元素后:
   A、b、c、d、e、aa、
   Process finished with exit code 0
 
2、ArrayList集合:

1、默认初始化容量为10。(底层先创建了,一个长度为0的数组,当添加第一个元素的时候,初始化容量为10)

  • ArrayList集合是非线程安全的,不是线程安全的集合。

2、ArrayList集合底层是一个Object[]数组。

3、构造方法:

  • new ArrayList();

  • new ArrayList(20);

4、ArrayList集 合的扩容: 扩容到原容量的1.5倍。

  • ArrayLIst集合怎么优化?
    • ArrayList集合底层是数组,数组扩容效率比较低,减少扩容。
    • 建议在使用ArrayList的时候预估计元素的个数,给定一个初始化容量。

5、数组的优缺点:

  • 优点:检索效率比较高。

    • 每个元素占用的空间相同,内存地址是连续的,知道元素的内存地址,通过数学表达式计算出元素的内存地址,所以检索效率最高。
  • 缺点
    1.随机增删元素的效率比较低,向数组末尾添加元素的效率还是很高的。
    2.数组无法存储大数据量。(很难找到巨大的连续内存空间。)

使ArrayList集合线程安全的方法
Collections.synchronizedList(集合对象);
3、linkedList集合(链表结构)
  • 没有初始化容量。
3.1、单向链表
  • (头节点:header、尾节点:last)
  • 基本单元是节点Node。
  • 节点中有两个属性:存储的数据,下一节点的内存地址。
  • 优点:随机增删元素效率较高(因为严肃不涉及到大量元素的位移)
  • 缺点:查询效率较低,每一次查找某个元素的时候都需要从头节点开始往下遍历。
3.2、双向链表
  • 多了一个前节点内存地址
3.3总结:
  1. LinedList集合是双向链表。
  2. 对于链表数据结构来说,随机增删效率较高,检索效率较低。
  3. 链表中的元素在空间存储上,内存地址不连续。
4、Vector
  • 默认容量10;当元素超过10,扩容后是原容量的2倍。

  • Vector中所有的方法都是线程同步的,都带有synchronized关键字,线程安全,但是效率较低。使用较少。

5、泛型

  • 泛型这种预发机制,只在程序编译的阶段起作用,只是给编译器参考。(运行阶段泛型没用)
    • 优点:
      1、集合中元素类型更加统一
      2、从集合中取出泛型指定的类型,不用大量的“向下转型”!

    • 缺点:
      1、使用泛型了之后,集合只能存放(集合允许存储的)泛型指定的元素类型,导致集合中存储的元素缺乏多样性!

:大多数业务中,集合中元素的类型还是同一的,多以这种泛型特性还是被大家所认可的。

1. 不使用泛型迭代集合示例
public class Generic01 {
    public static void main(String[] args) {
        //创建集合对象
        List list= new ArrayList();
        //创建元素
        father f=new father();
        boy1 b1=new boy1();
        boy2 b2=new boy2();

        //添加元素至集合
        list.add(f);
        list.add(b1);
        list.add(b2);

        //迭代集合
        Iterator it=list.iterator();
        while (it.hasNext()){
             //强制转换
           father obj=(father) it.next();
            obj.f1();
        }


    }

}
//准备对象类型
class  father{
    public void f1(){
        System.out.println("父类");
    }
}
class boy1 extends father{
    public void  b1(){
        System.out.println("子类1");
    }
}
class boy2 extends father{
    public void  b2(){
        System.out.println("子类2");
    }
}
  • 输出结果:
   	父类
   	父类
   	父类
//结果证明,并没有输出对象方法,只是输出内存地址
2、使用泛型迭代集合
 public static void main(String[] args) {
        //创建集合对象
        //<father>指定了集合对象能存储的元素只能father类型。
       List<father> list=new ArrayList<father>();
        //创建元素
        father f=new father();
        boy1 b1=new boy1();
        boy2 b2=new boy2();

        //添加元素至集合
        //使用泛型的短板是:
        list.add(b1);
        list.add(b2);

        //迭代集合
        //<father>表示迭代器是father类型。
         Iterator<father> it=list.iterator();
        while (it.hasNext()){
            //不用强制类型转换,直接就能调用。
            father fa=it.next();
          fa.f1();
            
             //调用子类特有方法
            father a=it.next();

            if(a instanceof boy1){
                boy1 bb1=(boy1)a;
                bb1.b1();
            }

            if(a instanceof boy2){
                boy2 bb2=(boy2)a;
                bb2.b2();
            }
        }
    }
}

//准备对象类型
class  father{
    public void f1(){
        System.out.println("父类");
    }
}
class boy1 extends father{
    public void  b1(){
        System.out.println("子类1");
    }
}
class boy2 extends father{
    public void  b2(){
        System.out.println("子类2");
    }
}
  • 输出结果:
   	父类
   	父类
   	父类
//结果一致。
3、钻石表达式
  • //List<father> mylist =new ArrayList<可以省略不写>();
    List<father> mylist=new ArrayList<>();
    
public class Generic03 {
    /*
    泛型
    自动类型推断机制又称(钻石表达式)
 */
    public static void main(String[] args) {
        //创建类型对象
        //ArrayList<这里会自动推断是什么类型>,前前提是JDK8之后才允许的。
        List<father> mylist=new ArrayList<>();
        //添加集合元素
        mylist.add(new father());
        mylist.add(new boy1());
        mylist.add(new boy2());
        //遍历集合
        Iterator<father> it=mylist.iterator();
        while (it.hasNext()){
            father f=it.next();
            f.f1();
        }
    }
}

4、自定义泛型
  • 自定义泛型的时候,<>中是一个表示符(可以随便写)。

  • java中源代码中经常出现的是:

      <E>和<T>
    
    • E是Element单词首字母。

    • T是Type单词首字母。

public class n_Generic04<标识符随便写>{
    //创建方法
    public void doSome(标识符随便写 o){
        System.out.println("已执行DoSOEM方法");
        System.out.println(o);
    }

    public static void main(String[] args) {
        //new对象的时候指定了泛型是:string类型
        n_Generic04<String> ng = new n_Generic04();

        //类型不匹配
        ng.doSome("ng——01标识符随便写");
    }
}

6、Set集合(接口)

  • 1、无序性:存取顺序不一致(没有下标,可以使用foreger循环遍历,foreger底层是用iterator迭代器实现的)
  • 2、元素不可重复:不可以存储重复元素
1.HashSet集合特点
  • 1、无序性:存取顺序不一致
  • 2、元素不可重复:不可以存储重复元素
  • 3、放到HashSet集合中的元素实际上是放到了hashMap集合的key部分了。
public class HashSetDome01 {

    public static void main(String[] args) {
        HashSet<String> strings = new HashSet<>();
        strings.add("String1");
        strings.add("String2");
        strings.add("String3");
        strings.add("String1");
        Iterator<String> it = strings.iterator();
        while (it.hasNext()){
            String s=it.next();
            System.out.println(s);
        }
        for (String s:strings){
            System.out.println(s);
        }

    }
}
/*输出结果:String3
		  String2
		  String1
*/
2.TreeSet集合

特点:

  • 无序不可重复

  • 自动排序由小到大、由前到后。

    public class TreeSetDome01 {
        /*
        treeSet集合存储元素特点:
            1、
         */
        public static void main(String[] args) {
            TreeSet<Integer> integer = new TreeSet<>();
            integer.add(5);
            integer.add(1);
            integer.add(2);
            integer.add(3);
            integer.add(4);
            for (int i:integer){
                System.out.println(i);
            }
        }
    }
    /*
    输出结果:1
            2
            3
            4
            5
     */
    

7、Map集合(接口)

  • 特点:无序不重复

    • 当key值重复时,value会覆盖
  • 1.Map和collection没有继承关系。

  • 2.Map集合以key和value的方式存储数据:键值对

    • key和value都是引用数据类型。
    • key和value都是存储对象的内存地址。
    • key起主导的地位,value是key的附属品。
1.Map集合中常用的方法
public static void main(String[] args) {
        //创建map集合
        Map<Integer, String> hm = new HashMap<>();
        //向map集合中添加键值对
        hm.put(1,"元素1");
        hm.put(2,"元素2");
        hm.put(3,"元素3");
        hm.put(4,"元素4");
        hm.put(5,"元素5");
        hm.put(6,"元素6");

        //通过key获取value
        hm.get(2);
        System.out.println(hm.get(2));

     //contains方法底层都是调用的equals方法
        //判断集合中是否包含指定key
        System.out.println(hm.containsKey(1));

        //判断集合中是否包含指定元素value
        System.out.println(hm.containsValue("元素1"));

        //判断集合中的元素是否为0
        System.out.println(hm.isEmpty());

        //获取Map集合中所有的key
        System.out.println(hm.keySet());

        //获取Map集合中所有的value
        System.out.println(hm.values());

        //通过key删除键值对
        hm.remove(1);

        //获取map集合中所有键值对的数量
        System.out.println(hm.size());

        //将map集合转换成set集合
        System.out.println(hm.entrySet());


        //清空map集合
        hm.clear();
        System.out.println(hm.size());
    }
}
2.遍历Map集合示例
  public static void main(String[] args) {
      //创建Map集合
      Map<Integer, String> hm = new HashMap<>();
      //添加键值对
      hm.put(1,"String1");
      hm.put(2,"String2");
      hm.put(3,"String3");
      hm.put(4,"String4");
      hm.put(5,"String5");
      //1、迭代器Map遍历
          /*
          1、首先拿到键值对的key,用set集合接收
          2、遍历集合set集合
          3、通过values方法获得key对应的value
           */
      Set<Integer> s=hm.keySet();
  
      Iterator<Integer> it=s.iterator();
      while (it.hasNext()){
          Integer i=it.next();
          System.out.println(i+"="+hm.get(i));
      }
  
      /*
      通过foreger增强型for循环遍历
      1、创建接收key的集合
      2、遍历集合set集合
      3、通过values方法获得key对应的value
       */
      Set<Integer> inte =hm.keySet();
      for(Integer in:inte){
          System.out.println(in+"="+hm.get(in));
      }
  }
3.HashMap(非线程安全)
  • (HashMap是对哈希表的一个应用实现)

  • HashMap的默认初始容量是16,默认加载因子是0.75.

  • 加载因子:当HashMap集合底层数组的容量达到75%的时候,数组开始扩容。

  • 哈希表是一个数组和单向链表的结合体。

    • 数组:在查询方面效率很高,随机增删方面效率很低。

    • 单向链表:在随机增删方面较高,查询方面很低。

    • 而哈希表将以上的两种数据结构融合在一起,充分发挥他们各自的优点。(并没有原数据结构高效的地方,高效)

  • **重点:**HashMap集合初始化容量为了达到效率均匀,提高集合存取率必须是2的倍数。

  • 当集合中的单向链表长度超过8的时候,单向链表这种结构会自动转换成红黑树数据结构。当红黑树上的节点小于6时,会重新把红黑树转换为单向链表这种结构。这种方式也是为了提高检索效率,二叉树的检索会再次缩小扫描范围,提高效率。

3.1、哈希表中的底层源码
public class HashMap{
    //HashMap底层实际上就是一个数组(一维数组)
    Node<K,V>[] table;

    //静态的内部类HashMap
    static  class Node<K,V>{
        final int hash;//哈希值:是key的HashCode()方法的执行结果。hash值通过哈希函数(算法)可以转换成数组的下标。
        final K key;//存储到Map集合中的key值。
        V value;//存储到Map集合中的value值。
        Node<K,V>next; //下个节点的内存地址
    }
3.2、添加键值对层原理(HashMap.put(value))
  1. 调用key的hashCode方法,获取哈希值。
  2. 哈希值通过哈希算法、函数,将hash值转换重数组下标。
  3. 如果下标没有没有任何元素,则把Node存储在此位置。
  4. 如果下标有对应的单向链表,此时就会用新节点的key值对比节点中的key值。
  5. 如果所有的equals方法都返回folse,则会吧新节点添加到单向链表结尾,如果equals方法返回true,则会覆盖对应节点的value。
3.3、获取键值对元素原理(HashMap.get(key))
  1. 调用key的hashCode方法,获取hash值。
  2. hash值通过哈希函数,计算出数组下标。
  3. 通过下标快速定位到数组的某个位置上。
  4. 如果此位置为空,则返回null。
  5. 如果此位置存在单向链表,那么获取节点的key值,和节点中的key值,进行equales方法比对。
  6. 如果equales方法返回false,那么get方法返回null、如果equales方法返回true,那么链表中与获取键值对对应的value,就是我们要找的value,get方法返回这个value。
3.4、特别注意:
  1. HashMap集合在添加、查询的时候,先后调用hashCode、equlae两个方法,那么这两个方法都需要重写。
  2. HashMap在使用不当,散列分布不均的时候,无法发挥性能,
    1. 假设有一百个元素,分布在由10个节点组成的10条链表上这就最均匀的,最好的(反之,则分散列布不均)。
  3. 哈希表:
    1. 如果两个键值对(元素)hash相等,那么这两个键值对一定会在一条单向链表上
    2. 如果不同,也有可能会在一条单向链表上。两个hash值有可能因为哈希算法之行结束之后转换的数组下标一样(哈希碰撞)。
    3. 哈希表扩容:原长度的2倍。
  4. HashMap集合中key值可以为Null。(只能有一个,不能违反hashMap的不可重复性)
4.hashCode与equals方法
  • Map集合在存取时,先调用hashCode方法在调用equales方法,

    • 什么时候不需要调用equales方法:存取时,调用hashCode方法,获取哈希值,在通过哈希函数(算法)获取书序下标,当下标为null时不需要调用equales方法。
  • 注意:

    • 1、如果equales方法重写,hashCode方法必须重写。
    • 2、如果equales方法返回true,那么hashCode方法必须返回true。
  • 结论:放在HashMap集合key部分,以及放在HashMSte集合中的元素都需要重写hashCode与equales方法。

5.HashTable集合
  • HashTbable集合的

    • 初始容量是1。
    • 扩容是,原容量的2倍+1。
    • key值与value值不允许为Null。
  • HashTable集合是线程安全的,其中所有的方法都带有synchronized关键字,效率较低,线程安全有别的办法,现在使用较少。

1.(子类)Properties集合
  • 注意:
    • properties集合的key与value值只能存储String类型的数据。
    • 通过key值获取value值的方法不同。
public static void main(String[] args) {
    //创建一个properties集合对象
    Properties ppt = new Properties();

    //添加元素(调用的还是HashTable的put方法)
    ppt.put("key1","value1");
    ppt.put("key2","value2");
    ppt.put("key3","value3");

    //通过key值获取对应的value值(获取的调用自己的properties方法)
    System.out.println(ppt.getProperty("key1"));
}
  • 输出结果:value1
6. TreeMap集合(Comparable接口)
  • 特点:

    • TreeSte集合中的元素:无序不可重复。
    • TreeSte集合中的元素:可以自动通过元素的自然大小排序。
  • 注意:

    • treeSet集合底层是把元素存储在了TreeMap集合中给的key部分中。

    • TreeMap集合底层实际上是一个二叉树结构。

  • TreeSet集合自定义类型示例

    public class TreeSetText03 {
        public static void main(String[] args) {
            //创建集合对象
            TreeSet<Vip> svip = new TreeSet<>();
            //创建、添加元素
            Vip v1 = new Vip("张三",12);
            Vip v2 = new Vip("李大爷",56);
            Vip v3 = new Vip("关孙子",20);
            Vip v4 = new Vip("丑龙",12);
            svip.add(v1);
            svip.add(v2);
            svip.add(v3);
            svip.add(v4);
            for (Vip v:svip){
                System.out.println(v);
            }
        }
    }
    		/*
        输出结果:
            Vip{name='丑龙', age=12}
            Vip{name='张三', age=12}
            Vip{name='关孙子', age=20}
            Vip{name='李大爷', age=56}
             */
    
    • 对象类型(注意三点)

      • 实现Comparable接口。

      • 重写比较(排序)规则compareTo方法。

      • 重写ToString方法。

    • **特别重要:**compareTo方法的返回值

      • 等于0:value值会覆盖。
      • 小于0:会在右子树上找。
      • 大于0:会在左子树上找。
    public class Vip implements Comparable<Vip>{
    
        private String name;
        private int age;
    //传参构造方法
        public Vip(String name, int age) {
            this.name = name;
            this.age = age;
        }
    //重写通String方法
        @Override
        public String toString() {
            return "Vip{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    //重写compareTo方法(排序规则)
        @Override
        public int compareTo(Vip o) {
                return this.age - o.age;
        }
    
  • 嵌套排序示例:安照年龄排序相等年龄的人在按姓名排序。

    • 与上不同的是,在compareTo方法中多调用了String的compareTo方法比较String类型的姓名。
public class Vip implements Comparable<Vip>{

    private String name;
    private int age;

    public Vip(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Vip{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int compareTo(Vip o) {
        if(this.age==o.age){
            return this.name.compareTo(o.name);
        }else {
            return this.age - o.age;
        }
    }
}
7.二叉树
  • 存储:遵循左小右大的存储原则,每次储存的时候都会和根比较,存放的过程就是排序的过程。

  • 遍历:(根在前是前序、根在中是中序、根在后是后序)

    • 前序遍历:根左右
    • 中序遍历:左根右(遍历出来的值会自动按大小排序)
    • 后序遍历:左右根
  • TreeSte、TreeMap集合和Iterator迭代器,采用的都是中序遍历:左根右。

  • 大致结构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fHUM2wqY-1596031592043)(C:\Users\000\AppData\Roaming\Typora\typora-user-images\image-20200729161759237.png)]

8.自定义比较器(Comparator)
1、建立Comparator比较器(两种方法)
  • implements Comparator比较器类型并指定泛型
  • 重写 Comparator自定义比较器中的Compare比较方法
class PeopleComparator implements Comparator<People> {
      @Override
      public int compare(People o1, People o2) {
          return o1.age-o2.age;
      }
  }
2、匿名内部类建立
  • 在新建集合的时候,直接以匿名内部类的方式插入Comparator比较器
  • 并在内重写 Comparator自定义比较器中的Compare比较方法
TreeSet<People> peo = new TreeSet<>(
       //在新建集合的时候传进一个Comparator比较器
        new Comparator<People>() {
        @Override
        public int compare(People o1, People o2) {
            return o1.age-o2.age;
        }
    });
  • Comparator比较器的使用
  • 在新建集合的时候传入使用
public class TreeMapComparator01 {
    public static void main(String[] args) {

        //创建集合
        TreeSet<People> peo = new TreeSet<>(new comparator<People>());
        //添加People类型元素
        peo.add(new People(12));
        peo.add(new People(11));
        peo.add(new People(14));
        peo.add(new People(10));
        //遍历集合
        for(People i:peo){
            System.out.println(i);
        }
    }
}

//创建人类,有年龄属性
class People{
    int age;
	//有参构造器
    public People(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "People{" +
                "age=" + age +
                '}';
    }
}
//创建Comparator比较器
class PeopleComparator implements Comparator<People> {
      @Override
      public int compare(People o1, People o2) {
          return o1.age-o2.age;
      }
  }
  • Comparator与Comparable比较器的区别
    • Comparatble是接口,如果规则是一成不变的建议使用
    • Comparator是自定义比较器,灵活一些,对于多、变的规则,建议使用。

8、Collections工具类

  • 注意点:Collection是接口,而Collections是集合的工具类。
1.Sort方法:
  • List集合的排序方法
2.synchronized*( * :集合类型)方法
  • 转换成线程安全的

    public class CollectionsTest01 {
        public static void main(String[] args) {
    
            //新建一个ArrayList集合
            ArrayList<String> al = new ArrayList<>();
    
            //添加元素
            al.add("adf");
            al.add("bdf");
            al.add("cf");
            al.add("adf");
    
            //变成线程安全的
            Collections.synchronizedList(al);
    
            //调用Collections中的方法排序
            Collections.sort(al);
            //遍历集合
            for(String s:al){
                System.out.println(s);
            }
            System.out.println("==============================");
    
            //新建一个自定义泛型list集合
            ArrayList<guisun> gs = new ArrayList<>();
            gs.add(new guisun("龟儿1"));
            gs.add(new guisun("龟儿2"));
            gs.add(new guisun("龟儿4"));
            gs.add(new guisun("龟儿1"));
            gs.add(new guisun("龟儿3"));
    
            //自定义类型排序时注意:对list集合中元素排序,需要保证list集合中的元素实现了比较器:Comparable接口、指定准确泛型。
            Collections.sort(gs);
            for (guisun g:gs){
                System.out.println(g);
            }
    
            System.out.println("=================测试Set集合=============");
    
            Set<String> set = new HashSet<>();
            set.add("3");
            set.add("9");
            set.add("0");
            set.add("7");
            set.add("4");
            //Collections中的sort方法只能对List集合排序。
            //将set集合转换成list集合
            List<String> setlist = new ArrayList(set);
            Collections.sort(setlist);
    
            for (String l:setlist){
                System.out.println(l);
            }
    
        }
    }
    

//创建自定义元素类型
//注意指定泛型,(默认的不一定是你需要的)
class guisun implements Comparable{
private String name;

   @Override
   public String toString() {
       return "guisun{" +
               "name='" + name + '\'' +
               '}';
   }

   public guisun(String name) {
       this.name = name;
   }

   public guisun() {

   }


   @Override
   public int compareTo(guisun o) {
       return this.name.compareTo(o.name);
   }

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值