Java 集合基础

Java 集合基础

1.集合基础

1.1集合概述

编程的时候如果要存储多个数据,使用长度固定的数组存储格式,不一定满足我们的需求,更适应不了变化的需求,要是想要长度可以变化的存储格式,数组就不行了,这个时候就需要集合

集合类的特点:提供一种存储空间可变的存储模型,存储的数据容量可以发生改变

集合

  • Collection接口(单列集合)
    • List接口(元素内容可重复)
      • ArrayList(实现类)
      • LinkedList(实现类)
    • Set接口(元素内容不可重复)
      • HashSet(实现类)
      • TreeSet(实现类)
  • **Map接口 ** (双列集合)
    • HashMap(实现类)

2. ArrayList

2.1 ArrayList 概述

在java.util包下

  • 调整大小的数组实现
  • :是一种特殊的数据类型,泛型

**用法:**在出现E的地方我们使用引用数据类型替换即可

举例:ArrayList , ArrayList

2.2 ArrayList构造方法和添加方法

方法名说明
public ArrayList( )创建一个空的集合对象
public boolean add(E e)将指定元素追加到这个集合末尾
public void add(int index , E element)在此集合的指定位置插入指定的元素
import java.util.ArrayList;

public class test {
    public static void main(String[] args) {
        //public ArrayList( )  创建一个空的集合对
        //ArrayList<String> array = new ArrayList<>();//jdk7之后,后面的<>可以不写内容,
        ArrayList<String> array = new ArrayList<String>();
        System.out.println("array:"+array);//输出:array:[]


        //public boolean add(E e)将指定元素追加到这个集合末尾,添加成功返回boolean值
        array.add("hello");
        array.add("java");
        array.add("best");
        System.out.println("array:"+array);//输出:array:[hello, java, best]


        //public void add(int index , E element)在此集合的指定位置插入指定的元素,指定位置的元素都往后移
        array.add(1,"javase");
        //array.add(7,"javaee");//IndexOutOfBoundsException
        System.out.println("array:"+array);//输出:array:[hello, javase, java, best]

    }
}

2.3 ArrayList集合的常用方法

方法名说明
public boolean remove(Object o)删除指定元素,返回删除是否成功
public E remove (int index)删除指定索引处的元素,返回被删除的元素
public E set(int index,E element)修改指定索引处的元素,返回被修改的元素
public E get(int index)返回指定索引处的元素
public int size()返回后集合中的元素个数
import java.util.ArrayList;
public class test {
    public static void main(String[] args) {
       ArrayList<String> array = new ArrayList<String>();
       //添加
       array.add("java");
       array.add("javase");
       array.add("javaee");
       array.add("hello");
        System.out.println(array);

        //public boolean remove(Object o) 删除指定元素,返回删除是否成功
        System.out.println(array.remove("hello"));//true
        System.out.println(array); //[java, javase, javaee]

        //public E  remove (int index) 删除指定索引处的元素,返回被删除的元素
        System.out.println(array.remove(1));//javase
        //System.out.prtinln(9);//IndexOutOfBoundsException
        System.out.println(array);//[java, javaee]
        
        //public E set(int index,E element)修改指定索引处的元素,返回被修改的元素
        System.out.println(array.set(1,"lllll"));//javaee
        System.out.println(array);//[java, lllll]

        //public E get(int index)返回指定索引处的元素
        System.out.println(array.get(0));//java
        //要是下标越界就会异常
        
        //public int size()返回后集合中的元素个数
        System.out.println(array.size());//2
    }
}

ArrayList对类的操作

public class test {
    public static void main(String[] args) {
        ArrayList<Student> arrs = new ArrayList<Student>();
        arrs.add(new Student("lll", 20));
        arrs.add(new Student("rrr", 23));
        for(int i=0;i<arrs.size();i++){
            System.out.println(arrs.get(i).getName()+" "+arrs.get(i).getAge());
        }

    }
}

3. Collection(单列集合)

张三
李四
王五

3.1 Collection集合的概述和使用

Collection集合的概述

  • 是单列集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
  • JDK不提供此类的任何直接实现,它提供更具体的子接口(如Set和List)实现

创建Collection集合的对象

  • 多态的方式(父类对象指向子类)
  • 具体的实现类ArrayList
import java.util.ArrayList;
import java.util.Collection;
public class test {
    public static void main(String[] args) {
        //创建Collection集合的对象,用多态的方法
        Collection<String> c = new ArrayList<String>();

        //添加元素 boolean add (E e)
        c.add("hello");
        c.add("world");
        c.add("java");

        //输出集合对象,重写了toString方法
        System.out.println(c);//输出:[hello, world, java]
    }
}

3.2 Collection集合常用方法

方法名说明
boolean add (E e)添加元素
boolean remove (Object o)从集合中移除指定的元素
void clear( )清空集合中的元素
boolean contains(Object o)判断集合中是否存在指定的元素
boolean isEmpty( )判断集合是否为空
int size( )集合的长度,也就是集合中元素的个数
import java.util.ArrayList;
import java.util.Collection;
//Alt + 7可以打开一个窗口,看到类的所有消息
public class test {
    public static void main(String[] args) {
        //创建Collection集合的对象,用多态的方法
        Collection<String> c = new ArrayList<String>();

        //添加元素 boolean add (E e)
        c.add("hello");
        c.add("world");
        System.out.println(c.add("world"));//如果添加成功就返回true
        //输出:true
        //对于Collection的ArrayList来说,调用add永远返回true

        //输出集合对象,重写了toString方法
        System.out.println(c);//输出:[hello, world, world],可以存储重复元素


        //boolean remove (Object o) 从集合中移除指定的元素
        System.out.println(c.remove("hello"));//true
        System.out.println("java");//false
        System.out.println(c);//[world, world]

        //int size( ) 集合的长度,也就是集合中元素的个数
        System.out.println(c.size());//2


        //boolean contains(Object o)判断集合中是否存在指定的元素
        System.out.println(c.contains("world"));//true
        System.out.println(c.contains("java"));//false

        //void clear( ) 清空集合中的元素
        c.clear();
        System.out.println(c);//输出:[]
        //boolean isEmpty( )判断集合是否为空
        System.out.println(c.isEmpty());//true清空后,集合为空,返回true
    }
}

3.3 Collection集合的遍历

3.3.1 Iterator 迭代器(是一个接口)

Iterator:迭代器,集合的专用遍历方式

  • Iterator iterator( ): 返回此集合中元素的迭代器,通过集合的iterator( )方法得到
  • 迭代器是通过集合的iterator( )方法得到的,所以迭代器是依赖于集合存在的。

Iterator中的常用方法

  • E next( ):返回迭代中的下一个元素
  • boolean hasNext( ):如果迭代具有更多元素,则返回true
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class test {
    public static void main(String[] args) {
        Collection<String> c =new ArrayList<String>();

        c.add("hello");
        c.add("java");
        c.add("world");

        //Iterator<E> iterator( ): 返回此集合中元素的迭代器,通过集合的iterator( )方法得到
        Iterator<String> it = c.iterator();

        //E next()返回迭代器下一个元素
        /*System.out.println(it.next());
        System.out.println(it.next());
        System.out.println(it.next());
        System.out.println(it.next());//NoSuchElementException 被请求的元素不存在*/

        if(it.hasNext()){
            System.out.println(it.next());
        }//这样写就不会抛出异常


        //用while循环改进
        while(it.hasNext()){
//            System.out.println(it.next());
            String s= it.next();
            System.out.println(s);
        }
        //输出:
        // hello
        //java
        //world

    }
}

3.4 集合的使用步骤

  • 步骤1:创建集合对象
  • 步骤2:添加元素
    • 步骤2.1:创建元素
    • 步骤2.2:添加元素到集合
    • 合并:添加元素到集合
  • 步骤3:遍历集合
    • 步骤3.1:通过集合对象获取迭代器对象
    • 步骤3.2:通过迭代器对象的hasNext( )方法判断是否还有元素
    • 步骤3.3:通过迭代器对象的next( )方法获取下一个元素
public class test {
    public static void main(String[] args) {
        Collection<String> c =new ArrayList<String>();

       String s = "lalala";
       c.add(s);

       Iterator<String> it = c.iterator();
        while (it.hasNext()) {
            String str = it.next();
            System.out.println(str);
        }

    }
}

4. List

4.1 List 集合概述和特点

在java.util包下

List集合概述

  • 有序集合(也称为序列),用户可以精确控制列表中每一个元素的插入位置。用户可以通过整数索引访问元素,并搜索列表中的元素
  • 与Set集合不同。列表通常允许重复的元素

List集合的特点:

  • 有序:存储和取出的元素顺序一致
  • 可重复:存储的元素可以重复
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

public class test {
    public static void main(String[] args) {
        //创建List集合对象,用多态的方式,父类对象指向子类,因为List没有构造方法,只是一个接口
        List<String> l = new ArrayList<>();

        //添加
        l.add("javase");
        l.add("javaee");
        l.add("java");
        l.add("java");

        //迭代器遍历List
        Iterator<String> it = l.iterator();
        while(it.hasNext()){
            String s= it.next();
            System.out.println(s);
            /*
            输出:
            javase
            javaee
            java
            java
             */
        }
     }
}

4.2 List集合特有方法(同ArrayList)

方法名说明
void add(int index,E element)在此集合中指定位置插入指定的元素
E remove(int index)删除指定索引处的元素,返回被删除的元素
E set(int index,E element)修改指定索引处的元素,返回被修改的元素
E get(int index)返回指定索引处的元素
mport java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

public class test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("java");
        list.add("hello");
        list.add("javaee");

// void add(int index,E element)  在此集合中指定位置插入指定的元素
       list.add(1,"javase");
//       list.add(11,"jaaaa");异常报错,IndexOutOfBoundsException
        System.out.println(list);


//E remove(int index) 删除指定索引处的元素,返回被删除的元素
        list.remove(1);
//        list.remove(11);IndexOutOfBoundsException
        System.out.println(list);


//E set(int index,E element) 修改指定索引处的元素,返回被修改的元素
        list.set(2,"javabest");
//        list.set(11,"hello");IndexOutOfBoundsException
        System.out.println(list);


//E get(int index)  返回指定索引处的元素
        System.out.println(list.get(1));
//        System.out.println(list.get(11));IndexOutOfBoundsException

        //利用索引遍历list
        for(int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }

    }


    /*
    输出:
    [java, javase, hello, javaee]
    [java, hello, javaee]
    [java, hello, javabest]
    hello
     */
}
//遍历Student类
//迭代器遍历
while(it.hasNext()){
    Student s =it.next();
    System.out.println(it.getName()+it.getAge());
}
//for循环遍历
for(int i=0;i<list.size();i++){
    Student s =list.get(i);
    System.out.println(it.getName()+it.getAge());
}

4.3 并发修改异常

  • ConcurrentModificationException报出异常,当不允许这样修改时,可以检测到对象的并发修改方法来抛出异常
    

产生原因:

  • 迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成迭代器获取元素中判断预期修改值和实际修改值不一致,这里详见IT黑马

解决方案

  • 用for循环遍历,然后用集合对象做对应的操作即可
/*
需求:
有一个List集合
里面有三个元素"hello","world","java"
遍历集合,每得到一个元素,看看有没有”world“这个单词,如果有,我们就添加”javaee“元素
ConcurrentModificationException报出异常,当不允许这样修改时,可以检测到对象的并发修改方法来抛出异常
 */
public class test {
    public static void main(String[] args) {
        //有一个List集合
        List<String> list = new ArrayList<String>();
        //里面有三个元素"hello","world","java"
        list.add("hello");
        list.add("world");
        list.add("java");

        //遍历集合,每得到一个元素,看看有没有”world“这个单词,如果有,我们就添加”javaee“元素
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String s = it.next();//这里出了异常
            if(s.equals("world")){
                list.add("javaee");
            }
        }
        //ConcurrentModificationException报出异常,当不允许这样修改时,可以检测到对象的并发修改方法来抛出异常


        //可以用for循环代替来解决问题
        for(int i=0;i<list.size();i++){
            String s= list.get(i);
            if(s.equals("world")){

            }
        }
        System.out.println(list);
    }
}

4.4 ListIterator

ListIterator:列表迭代器,在java.util

  • 通过List集合的listIterator()方法得到,所以说它是List集合特有的迭代器
  • 用于允许程序员沿任意方向遍历列表的列表迭代器,在迭代期间修改列表,,并获取列表中迭代器的当前位置

ListIterator中的常用方法

  • E next():返回迭代中的下一个元素
  • boolean hasNext():如果迭代具有更多元素,则返回true
  • E previous():返回列表中的上一个元素
  • boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true
  • void add(E e):将指定元素插入列表
import java.util.*;
public class test {
    public static void main(String[] args) {
        //有一个List集合
        List<String> list = new ArrayList<String>();
        //里面有三个元素"hello","world","java"
        list.add("hello");
        list.add("world");
        list.add("java");


/*
        //ListIterator迭代器
        ListIterator<String> lit = list.listIterator();
//        E next():返回迭代中的下一个元素
//        boolean hasNext():如果迭代具有更多元素,则返回true
        while(lit.hasNext()){
            String s = lit.next();
            System.out.println(s);
        }
        System.out.println("-----------------");
//        E previous():返回列表中的上一个元素
//        boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回true
        while(lit.hasPrevious()){
            String s = lit.previous();
            System.out.println(s);
        }
        输出:
        hello
        world
        java
        -----------------
        java
        world
        hello

*/


        //ListIterator最主要的功能时可以弥补Iterator的并发修改异常
        ListIterator<String> lit = list.listIterator();
        while(lit.hasNext()){
            String s= lit.next();
            if(s.equals("world")){
                lit.add("javaee");//注意:是在当前这个下标值后面追加信息
            }
        }
        System.out.println(list);//[hello, world, javaee, java]
        

    }

}

4.5 增强for循环

增强for循环:简化数组和Collection集合的遍历

  • 实现Iterator接口的类允许其对象成为增强型for语句的目标
  • 它是JDK5之后出现的,其内部原理是一个Iterator迭代器

增强for的格式:

  • 格式:

for(元素数据类型 变量名 :数组或者Collection集合){

//在此处使用变量即可,该变量就是元素

}

public static void main(String[] args){
    //数组
    int[] arr = {1,2,3,4,5};
    for(int i:arr){
        System.out.println(i);
    }
    //集合
    List<String> list = new ArrayList<String>();
    list.add("hello");
    list.add("java");
    for(String s : list){
        System.out.println(s);
    }
    
    //内部是一个Iterator迭代器
    for(String s : list){
        if(s.equals("world")){
            list.add("java");
        }
    }//这里抛出并发修改异常
    
}

4.6 常用数据结构

栈:后进先出,先进后出

队列:先进先出,后进后出

数组:查询快,增删慢

链表:查询慢,增删快

4.7 List集合子类特点

List常用子类:ArrayListLinkedList

  • ArrayList:底层数据结构是数组,查询快,增删慢。
  • LinkedList:底层数据结构是链表,查询慢,增删快。

两个子类的用法相同,但是特点不同

  • ArrayList
public class test {
    public static void main(String[] args) {
        //ArrayList
        ArrayList<String> arr = new ArrayList<String>();
        //add
        arr.add("hello");
        arr.add("java");
        arr.add("world");
        //遍历
        for (String s : arr) {
            System.out.println(s);
        }
    }
}
  • LinkedList
public class test {
    public static void main(String[] args) {
        //LinkedList
        LinkedList<String> linklist = new LinkedList<String>();
        //add
        linklist.add("hello");
        linklist.add("java");
        linklist.add("world");
        //遍历
        for (String s : linklist) {
            System.out.println(s);
        }
    }
}

4.8 LinkedList集合的特有功能

方法名说明
public void addFirst(E e)在该列表开头插入指定元素
public void addLast(E e)将指定元素追加到此列表的末尾
public E getFirst()返回此列表的第一个元素
public E getLast()返回此列表的最后一个元素
public E removeFirst()从此列表中删除并返回第一个元素
publci E removeLast()从此列表中删除并返回最后一个元素
public class test {
    public static void main(String[] args) {
        //LinkedList
        LinkedList<String> linklist = new LinkedList<String>();
        //add
        linklist.add("hello");
        linklist.add("java");
        linklist.add("world");
        System.out.println(linklist);//[hello, java, world]
//| public void addFirst(E e) | 在该列表开头插入指定元素         |
//| public void addLast(E e)  | 将指定元素追加到此列表的末尾     |
        linklist.addFirst("JAVAEE");
        linklist.addLast("JAVAsE");
        System.out.println(linklist);//[JAVAEE, hello, java, world, JAVAsE]

//| public E getFirst()       | 返回此列表的第一个元素           |
//| public E getLast()        | 返回此列表的最后一个元素         |
        System.out.println(linklist.getFirst());//JAVAEE
        System.out.println(linklist.getLast());//JAVAsE
//| public E removeFirst()    | 从此列表中删除并返回第一个元素   |
//| publci E removeLast()     | 从此列表中删除并返回最后一个元素 |
        linklist.removeFirst();
        linklist.removeLast();
        System.out.println(linklist);//[hello, java, world]
    }
}

5. Set

5.1 Set集合概述和特点

Set集合特点

  • 不包含重复元素的集合
  • 没有带索引方法,所以不能使用for循环遍历
  • HashSet迭代循序不做任何保证
public class test {
    public static void main(String[] args) {
        //创建Set集合,用多态的方式创建
        Set<String> set = new HashSet<String>();
        //添加元素,hashset不能保证按顺序输出
        set.add("hello");
        set.add("world");
        set.add("java");
        //没有重复元素
        set.add("java");

        //没有索引,不能用普通for循环遍历,需要用迭代器遍历
        for(String s : set){
            System.out.println(s);
        }
        /*
        输出:
        world
        java
        hello
        */

    }
}

5.2 哈希值

哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值

Object类中有一个方法可以获取对象的哈希值

  • public int hashCode():返回对象的哈希码值

对象的哈希值特点

  • 同一个对象多次调用hashCode()方法返回的哈希值是相同的
  • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同
public class test {
    public static void main(String[] args) {
        Student s = new Student("lhp",20);
        //同一个对象的hashcode相同
        System.out.println(s.hashCode());//460141958
        System.out.println(s.hashCode());//460141958

        //一般情况下,不同对象的hashcode不同
        //但是要是类中重写hashcode方法,就可以实现不同对象同一个hashcode
        Student s2= new Student("lrx",24);
        System.out.println(s2.hashCode());//1163157884


        System.out.println("java".hashCode());//3254818
        System.out.println("java".hashCode());//3254818
        System.out.println("world".hashCode());//113318802

        //这里字符产重写了hashcode
        System.out.println("重地".hashCode());//1179395
        System.out.println("通话".hashCode());//1179395
    }
}

5.3 HashSet集合概述和特点

HashSet集合特点

  • 底层数据结构是哈希表
  • 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出元素顺序一致
  • 没有带索引的方法,所以不能使用普通的for循环遍历
  • 由于是Set集合,所以是不包含重复元素的集合
public class test {
    public static void main(String[] args) {
        HashSet<String> hs = new HashSet<String>();

        //添加
        hs.add("java");
        hs.add("java");
        hs.add("javaee");
        hs.add("javase");
        //遍历
        for (String h : hs) {
            System.out.println(h);
        }
        /*
        输出:
        java
        javase
        javaee
         */
    }
}

HashCode存储元素:

  • 要保证元素的唯一性,需要重写hashCode()和equals()

5.4 数据结构之哈希表

哈希表

  • JDK8之前,底层采用数组+链表实现,可以说是一个元素为链表的数组
  • JDK8以后,在长度较长的时候,底层实现了优化

详见it黑马

5.5 HashSet集合存储学生对象(如果要保证唯一性,需要重写equals和hashcode方法)

public class Student {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //重写equals方法,可以让HashSet添加对象时表现出唯一性,不重复性
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }
//重写hashCode方法
    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}
public class test {
    public static void main(String[] args) {
        //创建关于学生的哈希表
        HashSet<Student> hs = new HashSet<Student>();
        //创建学生对象
        Student s1= new Student("lhp",20);
        Student s2 = new Student("zkt",21);
        Student s3= new Student("lhp",20);
        //hashset添加对象
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        //遍历
        for (Student h : hs) {
            System.out.println("name:"+ h.getName()+"  age:"+ h.getAge());
        }

        /*
        没有重写equals方法前:
        name:lhp  age:20
        name:zkt  age:21
        name:lhp  age:20
         */

        /*
        重写equals方法后:
        name:lhp  age:20
        name:zkt  age:21
         */
    }
}

5.6 LinkedHashSet集合概述和特点

LinkedHashSet集合特点:

  • 哈希表和链表实现的Set接口,具体有可预测的迭代次序
  • 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
  • 由哈希表保证元素唯一,也就是说没有重复的元素
public class test {
    public static void main(String[] args) {
        //创建集合
      LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
      //添加元素
        linkedHashSet.add("java");
        linkedHashSet.add("java");
        linkedHashSet.add("javaEE");
        linkedHashSet.add("javaSE");
        //遍历
        for (String s : linkedHashSet) {
            System.out.println(s);
        }
        /*
        输出:
        java
        javaEE
        javaSE

         */
    }
}

5.7 TreeSet集合概述和特点

TreeSet集合特点:

  • 元素有序,这里的顺序不是指存储和取出顺序,而是按照一定规律进行排序,具体排序方式取决于构造方法
    • TreeSet():根据其元素的自然排序进行排序
    • TreeSet(Comparator comparator):根据指定的比较器进行排序
  • 没有索引的方法,所以不能使用普通for循环遍历
  • 由于Set集合,所以不包含重复元素的集合
public class test {
    public static void main(String[] args) {
        //创建对象
      TreeSet<Integer> tr = new TreeSet<Integer>();
        //添加成员
      tr.add(20);
      tr.add(10);
      tr.add(50);
      tr.add(30);
      tr.add(70);
      tr.add(20);
        //遍历
        for (Integer integer : tr) {
            System.out.println(integer);
        }
        /*
        输出:
        10
        20
        30
        50
        70
         */
    }
}

5.8 自然排序Comparable的使用

  • 存储学生对象并遍历,创建TreeSet集合使用无参构造方法
  • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
public class Student implements Comparable<Student>{
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //重写equals方法,可以让HashSet添加对象时表现出唯一性,不重复性
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
//!!!重写Coparable接口里面的方法
    @Override
    public int compareTo(Student o) {
//        return 0;//表示只添加一个元素
//        return 1;表示按正序添加和输出元素(升序)
//        return -1;//表示按逆序添加和输出元素(降序)
        int num1=this.age-o.age;
        int num2= num1==0?this.name.compareTo((o.name)):num1;//如果年龄相同就比姓名首字母
        return num2;
    }
}
public class test {
    public static void main(String[] args) {
        TreeSet<Student> tr = new TreeSet<Student>();

        Student s1 = new Student("lhp",20);
        Student s2 = new Student("arx",24);
        Student s3= new Student("zkt",19);
        Student s4= new Student("akt",19);


        tr.add(s1);
        tr.add(s2);
        tr.add(s3);
        tr.add(s4);

        //这里要实现接口Comparable,并且需要根据要求重写compareto
        for (Student student : tr) {
            System.out.println(student.getName()+" "+student.getAge());
        }

        /*
        输出:
        akt 19
        zkt 19
        lhp 20
        arx 24

         */

    }
}

结论:

  • 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
  • 自然排序,就是让元素所属的类实现Comparable接口,重写cmopareTo(T o)方法
  • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

5.9 比较器排序Comparable的使用

  • 存储学生对象并遍历,创建TreeSet集合使用有参构造方法
  • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
import java.util.*;
/*
- 存储学生对象并遍历,创建TreeSet集合使用**有参构造方法**
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
 */
public class test {
    public static void main(String[] args) {
        //创建集合的时候,使用有参构造
        TreeSet<Student> tr = new TreeSet<Student>(new Comparator<Student>() {
            //方法重写
            @Override
            public int compare(Student o1, Student o2) {
                //主要条件
                int num1=o1.getAge()-o2.getAge();
                //次要条件s
                int num2 = num1==0?o1.getName().compareTo(o2.getName()):num1;
                return num2;
            }
        });


        Student s1 = new Student("lhp",20);
        Student s2 = new Student("arx",24);
        Student s3= new Student("zkt",19);
        Student s4= new Student("akt",19);


        tr.add(s1);
        tr.add(s2);
        tr.add(s3);
        tr.add(s4);

        //这里要实现接口Comparable,并且需要根据要求重写compareto
        for (Student student : tr) {
            System.out.println(student.getName()+" "+student.getAge());
        }

        /*
        输出:
        akt 19
        zkt 19
        lhp 20
        arx 24

         */

    }
}

结论:

  • 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序
  • 比较器排序,就是让集合构造方法接收Comparator的实现对象,重写compare(T o1,T o2)方法
  • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

注意

Set set = new HashSet();//不会排序

SetSet=new TreeSet();//会排序

6. 泛型

6.1 泛型的概述

泛型:是JDK5中引入的特性,它提供了编译时类型安全检查机制,该机制允许在编译时检测到非法的类型,它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参,那么参数化类型怎么理解?

顾名思义,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型

这种参数类型可以用在类、方法和接口中,分别被称为泛型类,泛型方法、泛型接口**fanx

泛型定义格式:

  • <类型>:指定一种类型的格式。这里的类型可以看成是形参
  • <类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
  • 将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型

泛型的好处:

  • 把运行时期的问题提前到了编译期间
  • 避免了强制类型转换
public static void main(String[] args){
    Collection c = new ArrayList();//这里是object
    Collection<String> c = new ArrayList<String>();//这里是String泛型
    
    ....
    
}

6.2 泛型类

泛型类的定义格式:

  • 格式:修饰符 class 类名<类型>{ }
  • 范例:public class Generic{}
  • 此处T可以随便写为任意标识,常见的如T,E,K,V等形式的参数常用于表示泛型
public class Generic<T> {
    private T t;

    public Generic() {

    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}
public class test {
    public static void main(String[] args) {
        Generic<String> g = new Generic<String>();
        g.setT("lalala");
        System.out.println(g.getT());//输出lalala

        Generic<Integer> gg = new Generic<Integer>();
        gg.setT(100);
        System.out.println(gg.getT());//输出100
    }
}

6.3 泛型方法

泛型方法的定义格式:

  • 格式: 修饰符<类型> 返回值类型 方法名 (类型 变量名){ }
  • 范例: public < T> void show(T t){ }
public class Generic{
    //泛型方法
    public<T> void show(T t){
        System.out.println(t);
    }

}
public class test {
    public static void main(String[] args) {
        Generic g= new Generic();
        g.show(120);
        g.show("lhlp");
        g.show(true);
    }
    /*
    输出:
    120
    lhlp
    true
     */
}

6.4 泛型接口

泛型接口的定义格式:

  • 格式:修饰符 interface 接口名 <类型>{ }
  • 范例: public interface Generic { }
public interface Generic<T> {
    void show(T t);
}

public class Genericimpl<T> implements Generic<T> {
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}
public class test {
    public static void main(String[] args) {
        //通过类来实现和创建接口对象
        Generic<String> g = new Genericimpl<String>();
        g.show("llllpppp");//输出:llllpppp
    }
}

6.5 类型通配符

为了表示各种泛型List的父类,可以使用类型通配符

  • 类型通配符:<?>
  • List<?>:表示元素类型未知的List,它的元素可以匹配任何类型
  • 这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中

如果说我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限

  • 类型通配符上线:<? extends 类型>
  • List<? extends Number>:他表示的类型是Number或者其子类型

除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限

  • 类型通配符下限:<? super 类型>
  • List<?super Number>:他表示的类型是Number或者其父类型
public class test {
    public static void main(String[] args) {
        //类型通配符:**<?>**
       List<?> list1 = new ArrayList<Object>();
       List<?> list2 = new ArrayList<Number>();
       List<?> list3 = new ArrayList<Integer>();
       
       
        //类型通配符上线:**<? extends 类型>**
//        List<? extends Number> list4 =new ArrayList<Object>();报错
        List<? extends Number> list5=new ArrayList<Number>();
        List<? extends Number> list6=new ArrayList<Integer>();
        
        
        //类型通配符下限:**<? super 类型>**
        List<? super Number> list7 = new ArrayList<Number>();
//        List<? super Number> list8 = new ArrayList<Integer>();报错
        List<? super Number> list9 = new ArrayList<Object>();

    }
}

6.6 可变参数

可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了

  • 格式:修饰符 返回值类型 方法名(数据类型… 变量名)
  • 范例: public static int sum(int… a)

可变参数注意事项:

  • 这里的变量其实是一个数组
  • 如果一个方法有多个参数,包含可变参数,可变参数一定要放在最后
public class test {
    public static void main(String[] args) {
        System.out.println(sum(10,20,30));//60
        System.out.println(sum(10,20,30,40,50));//150;
        System.out.println(sum(10,20,30,40,50,60,70));//280
        System.out.println(sum(10,20,30,40,50,60,70,80,90));//450
    }

    public static int sum(int... a){
        int sum=0;
        for (int i : a) {
            sum+=i;
        }
        return sum;
    }
}

6.7 可变参数的使用

Arrays工具中有一个静态方法:

  • public static List asList(T… a):返回由指定数组支持的固定大小的列表
  • 返回的集合不能做增删操作,可以做修改操作
public class test {
    public static void main(String[] args) {
      List<String> list = Arrays.asList("hello","java","javaee");
      
//      list.add("javaee");//UnsupportedOperationException
//        list.remove("java");//UnsupportedOperationException
        list.set(0,"javaee");
        System.out.println(list);
        //无法增删,但是可以修改
        /*
        输出:[javaee, java, javaee]
         */
    }
}

List接口中有一个静态方法:

  • public static List of(E… elements):返回包含任意数量元素的不可变列表
  • 返回的集合不能做增删改操作
public static void main(String[] args){
    List<String> list= list.of("hello","java","javaee");
    //list.add("javase");//UnsupportedOperationException
    //list.remove("javaee");//UnsupportedOperationException
    //list.set(0,"ok");//UnsupportedOperationException
    //无法增删改
    System.out.println(list);
}

Set接口中有一个静态方法:

  • public static Set of(E… elements):返回一个包含任意数量元素的不可变列表
  • 在给元素的时候,不能给重复元素
  • 返回的集合不能做增删操作,没有修改操作
public static void main(String[] args){
   // Set<String> set = Set.of("world","world","java");//IllegalArgumentException
   Set<String> set = Set("world","java","hello");
    //set.add("javaee");
    //set.remove("world");
    System.out.println(set);
}

7. Map(双列集合)

001张三
002李四
003王五

7.1 Map集合概述和使用

Map集合概述

  • Interface Map<K,V> K:键值的类型; V:值的类型;
  • 将键映射到值的对象,不能包含重复的键,每个键可以映射到最多一个值
  • 举例:学生的学号和姓名

​ 001 mark

​ 002 jake

​ 003 leo

创建Map的对象

  • 多态的方式
  • 具体的实现类HashMap
public class test {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<String,String>();

        map.put("001","leo");
        map.put("002","nardor");
        map.put("003","lili");
        map.put("003","mike");//同一个键值出现两次,第二次会把第一次覆盖掉

        System.out.println(map);//{001=leo, 002=nardor, 003=mike}

    }

}

7.2 Map集合的基本功能

方法名说明
V put(K key,V value)添加元素
V remove(Object Key)根据键删除键值元素
void clear( )移除所有的键值元素
boolean containsKey(Object key)判断集合是否包含指定的键
boolean containsValue(Object key)判断集合是否包含指定的值
boolean isEmpty( )判断集合是否为空
int size( )集合的长度,也就是集合中键值对的个数
public class test {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<String,String>();
//V  put(K  key,V  value)             | 添加元素
        map.put("001","llll");
        map.put("002","lele");
        map.put("003","lplp");

//V  remove(Object Key)               | 根据键删除键值元素
        System.out.println(map.remove("001"));//输出:llll
        System.out.println(map.remove("004"));//输出:null

//boolean  containsKey(Object  key)   | 判断集合是否包含指定的键
        System.out.println(map.containsKey("002"));//true
        System.out.println(map.containsKey("005"));//false


//boolean  containsValue(Object  key) | 判断集合是否包含指定的值
        System.out.println(map.containsValue("llll"));//false
        System.out.println(map.containsValue("lele"));//true

//boolean  isEmpty( )                 | 判断集合是否为空
        System.out.println(map.isEmpty());//false

//int  size( )                        | 集合的长度,也就是集合中键值对的个数
        System.out.println(map.size());//2

//void  clear( )                      | 移除所有的键值元素
        System.out.println(map);//输出:{002=lele, 003=lplp}
        map.clear();
        System.out.println(map);//输出:{}
    }

}

7.3 Map集合的获取功能

方法名说明
V get(Object key)根据键获取值
Set keySet( )获取所有键的集合
Collection values( )获取所有值的集合
Set<Map.Entry<K,V> > entrySet( )获取所有键值对对象的集合
public class test {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();

        map.put("001", "llll");
        map.put("002", "lele");
        map.put("003", "lplp");

//V  get(Object  key)      | 根据键获取值
        System.out.println(map.get("001"));//llll
        System.out.println(map.get("004"));//null

//Set<K>  keySet( )        | 获取所有键的集合
        Set<String> keyset = map.keySet();
        for (String s : keyset) {
            System.out.println(s);
            /*
            输出:
            001
            002
            003
             */
        }

//Collection<V>  values( ) | 获取所有值的集合
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println(value);
            /*
            llll
            lele
            lplp
             */
        }
//Set<Map.Entry<K,V> >  entrySet( )获取所有键值对对象的集合
        Set<Map.Entry<String,String>> mapentry = map.entrySet();
//        2. 遍历键值对对象的集合,得到每一个键值对对象**用增强for实现,得到每一个Map.Entry**
        for (Map.Entry<String, String> entry : mapentry) {
            //        3. 根据键值对对象获取键和值:用**getKKey( )**得到键,用**getValue( )**得到值
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key+"  "+value);
        }
    }
}

7.4 Map集合的遍历

7.4.1遍历方法1:

把Map看成事夫妻对的集合

遍历思路:

  1. 把所有丈夫给集中起来

  2. 遍历丈夫的集合,获取到每一个丈夫

  3. 根据丈夫去找对应的妻子

转换为Map集合中的操作:

  1. 获取所有键的集合,用keySet() 方法实现

  2. 遍历键的集合,获取到每一个键。增强for实现

  3. 根据键去找值,用get(Object key)方法实现

public class test {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();

        map.put("001", "llll");
        map.put("002", "lele");
        map.put("003", "lplp");

//1. 获取所有键的集合,用keySet() 方法实现
        Set<String> keyset=map.keySet();

//2. 遍历键的集合,获取到每一个键。增强for实现
        for (String s : keyset) {
            //3. 根据键去找值,用get(Object  key)方法实现
            String values=map.get(s);
            System.out.println(s+"  "+values);
        }
        /*
        001  llll
        002  lele
        003  lplp
         */
    }
}
7.4.2 遍历方法2:

把Map看成是一个夫妻对

遍历思路:

  1. 获取所有结婚证的集合
  2. 遍历结婚证的集合,得到每一个结婚证
  3. 根据结婚证获取丈夫和妻子

转换为Map集合中的操作:

  1. 获取所有键值对对象的集合Set<Map.Entry<K,V> > entrySet( ):获取所有键值对对象的集合
  2. 遍历键值对对象的集合,得到每一个键值对对象用增强for实现,得到每一个Map.Entry
  3. 根据键值对对象获取键和值:
    1. 用**getKKey( )**得到键
    2. 用**getValue( )**得到值
public class test {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();

        map.put("001", "llll");
        map.put("002", "lele");
        map.put("003", "lplp");
//        1. 获取所有键值对对象的集合**Set<Map.Entry<K,V> > entrySet( ):获取所有键值对对象的集合**
        Set<Map.Entry<String,String>> mapentry = map.entrySet();
//        2. 遍历键值对对象的集合,得到每一个键值对对象**用增强for实现,得到每一个Map.Entry**
        for (Map.Entry<String, String> entry : mapentry) {
            //        3. 根据键值对对象获取键和值:用**getKKey( )**得到键,用**getValue( )**得到值
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key+"  "+value);
        }
    }
    /*
    001  llll
    002  lele
    003  lplp
     */
}
//Map.Entry看作是一个Map对象

7.5 典型案例

需求:创建一个HashMap集合,键是学生对象(student),值是居住地(String)。存储多个键值对元素,并且遍历,要求保证键的唯一性:如果学生对象的成员变量值相同,我们就认为是同一个对象

思路:

  1. 定义学生类
  2. 创建HashMap集合对象
  3. 创建学生对象
  4. 把学生添加到集合
  5. 遍历集合
  6. 在学生类中重写两个方法hashCode()和equals()
public class Student {
    private String Name;
    private int Age;

    public Student(String name, int age) {
        Name = name;
        Age = age;
    }

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    public int getAge() {
        return Age;
    }

    public void setAge(int age) {
        Age = age;
    }

    public Student() {
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (Age != student.Age) return false;
        return Name != null ? Name.equals(student.Name) : student.Name == null;
    }

    @Override
    public int hashCode() {
        int result = Name != null ? Name.hashCode() : 0;
        result = 31 * result + Age;
        return result;
    }
}
public class test {
    public static void main(String[] args) {
        Map<Student, String> map = new HashMap<Student, String>();

        Student s1 = new Student("www", 30);
        Student s2 = new Student("ttt", 33);
        Student s3 = new Student("jjj", 35);
        Student s4 = new Student("jjj", 35);
        //如果不重写学生类的两个方法,Set集合中相同的内容将无法覆盖
        /*不重写方法输出:
        jjj,35,河南
        ttt,33,浙江
        www,30,北京
        jjj,35,江苏
         */

        map.put(s1, "北京");
        map.put(s2, "浙江");
        map.put(s3, "河南");
        map.put(s4, "江苏");

        Set<Student> keyset = map.keySet();
        for (Student student : keyset) {
            String value = map.get(student);
            System.out.println(student.getName() + "," + student.getAge() + "," + value);
        }
        /*重写方法后的输出:
        www,30,北京
        jjj,35,江苏
        ttt,33,浙江
         */
    }
}

统计字符串中每个字符出现的次数

public class test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        //HashMap<Character,Integer> hm = new HashMap<Character, Integer>();无序版本
        TreeMap<Character,Integer> hm = new TreeMap<Character, Integer>();//有序版本

        for(int i=0;i<s.length();i++){
            Character key = s.charAt(i);
            Integer value = hm.get(key);
            if(value==null){
                hm.put(key,1);
            }else{
                value++;
                hm.put(key,value);
            }
        }
        //拼接
        StringBuilder sb = new StringBuilder();
        Set<Character> keyset = hm.keySet();
        for (Character character : keyset) {
            Integer value = hm.get(character);
            sb.append(character).append("(").append(value).append(")");
        }
        String res = sb.toString();
        System.out.println(res);

    }

}

7.6 集合嵌套

7.6.1 集合嵌套之ArrayList嵌套HashMap
  • ArrayLlist集合存储HahsMap元素并遍历

需求:创建一个ArrayList集合,存储三个元素,每一个元素都是HashMap,每一个HashMap的键和值都是String,并且遍历

思路:

  1. 创建ArrayList集合
  2. 创建HashMap集合,并添加键值对元素
  3. 把HashMap作为元素添加到ArrayList集合
  4. 遍历ArrayList集合
public class test {
    public static void main(String[] args) {
//        1. 创建ArrayList集合
        ArrayList<HashMap<String,String>> arrayList = new ArrayList<HashMap<String, String>>();
//        2. 创建HashMap集合,并添加键值对元素
        HashMap<String,String> hm1= new HashMap<String, String>();
        hm1.put("001","lll");
        hm1.put("002","ooo");

        HashMap<String,String> hm2= new HashMap<String, String>();
        hm2.put("001","rrr");
        hm2.put("002","ttt");

        HashMap<String,String> hm3= new HashMap<String, String>();
        hm3.put("001","vvv");
        hm3.put("002","qqq");
//        3. 把HashMap作为元素添加到ArrayList集合
        arrayList.add(hm1);
        arrayList.add(hm2);
        arrayList.add(hm3);

//        4. 遍历ArrayList集合
        for (HashMap<String, String> hashMap : arrayList) {//每一次都是一个hashmap
            //按照hashmap集合遍历的方式遍历
            Set<String> keyset = hashMap.keySet();
            for (String key : keyset) {
                String value = hashMap.get(key);
                System.out.println(key+","+value);
            }
        }
    }
}

7.6.2 集合嵌套之HashMap嵌套ArrayList
  • HashMap集合存储ArrayList元素并遍历

需求:创建一个HashMap集合,存储三个键值对元素,每一个键值对元素的键是String,值是ArrayList,每一个ArrayList元素是String,并且遍历

思路:

  1. 创建HashMap集合
  2. 创建ArrayList集合,并添加元素
  3. 把ArrayList作为元素添加到HashMap集合
  4. 遍历HashMap集合
public class test {
    public static void main(String[] args) {
//        1. 创建HashMap集合
        HashMap<String,ArrayList<String>> hashMap = new HashMap<String, ArrayList<String>>();
//        2. 创建ArrayList集合,并添加元素
        ArrayList<String> arr1 = new ArrayList<String>();
        arr1.add("javaee");
        arr1.add("javase");

        ArrayList<String> arr2 = new ArrayList<String>();
        arr2.add("C");
        arr2.add("C++");

        ArrayList<String> arr3 = new ArrayList<String>();
        arr3.add("HTML");
        arr3.add("CSS");
//        3. 把ArrayList作为元素添加到HashMap集合
        hashMap.put("JAVA",arr1);
        hashMap.put("CPP",arr2);
        hashMap.put("WEP",arr3);
//        4. 遍历HashMap集合
        Set<String> keyset= hashMap.keySet();
        for (String s : keyset) {
            ArrayList<String> value = hashMap.get(s);
            System.out.print(s+" ");
            for (String s1 : value) {
                System.out.print(s1+" ");
            }
            System.out.println();
        }
    }
    /*
    输出:
    JAVA javaee javase
    CPP C C++
    WEP HTML CSS
     */
}

8. Collections

8.1 Collections概述和使用

Collections类的概述

  • 是针对集合操作的工具类,类似于Arrays的用法,之间用类名调用方法

Collections类常用的方法

  • public static <T entends Comparable<? super T> > void sort(List list):将指定的列表按照升序排序
  • public static void reverse(List<?> list):反转指定列表中元素的顺序
  • public static void shuffle<List<?> list):使用默认的随机源随机排列指定的列表
public class test {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();

        list.add(10);
        list.add(4);
        list.add(30);
        list.add(25);
        list.add(100);

        System.out.println(list);//[10, 4, 30, 25, 100]

        //reverse反转
        Collections.reverse(list);
        System.out.println(list);//[100, 25, 30, 4, 10]
        //sort排序
        Collections.sort(list);
        System.out.println(list);//[4, 10, 25, 30, 100]

        //shuffl随机排序
        Collections.shuffle(list);
        System.out.println(list);//[30, 10, 25, 100, 4]

    }

}

案例:ArrayList存储学生对象并排序

需求:ArrayList存储学生对象,使用Collections对ArrayList进行排序

要求:按照年龄从小到大排序,年龄相同,按照姓名的字母顺序排序

(之前使用TreeSet实现的,现在用Collections实现)

思路:

  1. 定义学生类
  2. 创建ArrayList集合对象
  3. 创建学生对象
  4. 把学生添加到集合
  5. 使用Collections对ArrayList集合排序
  6. 遍历集合
public class test {
    public static void main(String[] args) {
//        1. 定义学生类
//        3. 创建学生对象
        Student s1 = new Student("lll",20);
        Student s2 = new Student("ooo",30);
        Student s3 = new Student("sss",19);
        Student s4 = new Student("kkk",19);

//        2. 创建ArrayList集合对象
//        4. 把学生添加到集合
        ArrayList<Student> stu = new ArrayList<Student>();
        stu.add(s1);
        stu.add(s2);
        stu.add(s3);
        stu.add(s4);
//        5. 使用Collections对ArrayList集合排序
        Collections.sort(stu,new Comparator<Student>(){
            @Override
            public int compare(Student o1, Student o2) {
                int num1=o1.getAge()-o2.getAge();
                int num2 = num1==0?o1.getName().compareTo(o2.getName()):num1;
                return num2;
            }
        });
//        6. 遍历集合
        for (Student student : stu) {
            System.out.println(student.getAge()+","+student.getName());
        }
        /*
        输出:
        19,kkk
        19,sss
        20,lll
        30,ooo
         */
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值