飞道的博客

《java学习笔记》之集合概述

216人阅读  评论(0)

集合

一.Collection接口

1.1 Collection的常用方法

public class CollectionTest01 {
    public static void main(String[] args) {
        //Collection 是所有 集合的父接口 ,是 Iterable 的子接口
        //学习各种集合之前先了解Collection的常用方法

        //Collection是接口,完全抽象的不能new对象
        //Collection collection =new Collection();//'Collection' is abstract; cannot be instantiated

        //多态
        //创建了一个ArrayList的集合对象
        Collection arrayList =new ArrayList();

        //boolean add(Object e)  向集合中添加元素
        //集合中不能直接存储基本类型结构,也不能存储java对象,只是存储java对象的内存地址
        arrayList.add(123);//自动装箱,变成了Integer对象
        arrayList.add(true);//自动装箱
        arrayList.add("????");//String对象
        arrayList.add(new m());//m对象
        arrayList.add(new Object());//Object 对象


        //int size()       获取集合中元素个数
        //不是集合长度,是集合内部元素的个数
        System.out.println("arrayList里面有" + arrayList.size() + "个元素");//arrayList里面有5个元素


        //boolean contains(Object o)     集合是否包含某元素
        System.out.println("arrayList里面有123? " +arrayList.contains(123));//arrayList里面有123? true
        System.out.println("arrayList里面有456? " +arrayList.contains(456));//arrayList里面有456? false


        //boolean remove(Object o)    从集合类删除某个元素
        //先删除123
        arrayList.remove(123);
        System.out.println("arrayList里面有" + arrayList.size() + "个元素");//arrayList里面有4个元素
        System.out.println("arrayList里面有123? " +arrayList.contains(123));//arrayList里面有123? false


        //Object[] toArray()    把集合转化成数组
        Object[] objects = arrayList.toArray();
        //遍历
        for (Object o : objects){
            System.out.print(o + " ");//true ???? caopeng.bolgTest.m@668bc3d5 java.lang.Object@3cda1055
        }

        System.out.println();


        //boolean isEmpty()     判断集合中的元素是否为0
        System.out.println("arrayList里面的元素个数是否为零 " + arrayList.isEmpty());//arrayList里面的元素个数是否为零 false


        //void clear()          移除集合中所有元素
        arrayList.clear();
        System.out.println("arrayList里面的元素个数是否为零 " + arrayList.isEmpty());//arrayList里面的元素个数是否为零 true
    }
}

class m{

}

1.2 Collection的迭代

//关于集合的遍历/迭代专题
public class CollectionTest02 {
    public static void main(String[] args) {
        //注意:以下讲解的遍历方式/迭代方式,所有Collection通用的一种方式
        //在Map集合不可用,在所有的Collection以及子类中使用
        //创建集合对象
        Collection arrayList =new ArrayList();//ArrayList是有序可重复,放进去和取出来是一样的顺序
        //添加集合元素
        arrayList.add("1");
        arrayList.add("2");
        arrayList.add("3");
        arrayList.add("4");
        arrayList.add("5");
        arrayList.add(new Object());
        arrayList.add("abc");

        //遍历/迭代集合
        Iterator iterator = arrayList.iterator();
        /*
            以下两个方法是迭代器Iterator中的方法:
         boolean hasNext()     如果仍有元素可以迭代,则返回 true。
          Object next()       返回迭代的下一个元素。
        */
        while (iterator.hasNext()){
            Object o = iterator.next();
            System.out.println(o);
            /*1
              2
              3
              4
              5
              java.lang.Object@2d209079
              abc
              */
        }
        /*//如果一直循环
        //java.util.NoSuchElementException
        while(true){
            Object o = iterator.next();
            System.out.println(o);
        }*/

        //再来试一下Set的迭代
        Collection hashSet= new HashSet();//HashSet  无序不可重复,存进去这个顺序,取出来就不一定这个顺序了
        hashSet.add(10);
        hashSet.add(20);
        hashSet.add(30);
        hashSet.add(30);
        hashSet.add(40);
        hashSet.add(20);
        hashSet.add(10);
        //迭代
        Iterator iterator1 = hashSet.iterator();
        while (iterator1.hasNext()){
            System.out.println(iterator1.next());
            /*
            20
            40
            10
            30
             */
        }
    }
}

1.3 Collection方法中contains方法深入

import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;

/*深入Collection的contains方法
 * *       boolean contains(Object o)     集合是否包含某元素
 *       底层调用了equals方法
 * 放在集合里面的类型要重写equals方法
 */
public class CollectionTest03 {
    public static void main(String[] args) {
        Collection arrayList = new ArrayList();
         String str1 = "abc";
         String str2 = "def";

         arrayList.add(str1);
         arrayList.add(str2);

         //集合中元素的个数
        System.out.println(arrayList.size());//2

        String str3 =new String("abc");

        //很明显 str3和 str1 的内存地址肯定不同
        //所以contains底层调用了equals方法
        System.out.println(arrayList.contains(str3));//true


        //创建两个学生对象
        Student student1 = new Student("钢铁侠");
        Student student2 = new Student("钢铁侠");
        //清空集合
        arrayList.clear();
        arrayList.add(student1);
        //重写equals方法之前
        //System.out.println(arrayList.contains(student2));//false
        //student1 和 student2名字一样,我们可以认为是一个学生,所以这里达不到我们的要求
        //我们就要在Student类里面重写equals方法
        System.out.println(arrayList.contains(student2));//true

        //remove()
        arrayList.remove(student2);
        //删除arrayList中的student2,但是student1没了,表示remove()方法底层调用的也是equals()方法
        System.out.println(arrayList.size());//0
    }
}

//Student类
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;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(name, student.name);
    }

}

1.4 Collection方法中remove()方法深入

public class CollectionTest04 {
    public static void main(String[] args) {
        Collection arrayList = new ArrayList();

        //如果集合机构发生了改变,但是不重新获取新的迭代器就会:
        //java.util.ConcurrentModificationException
        //Iterator iterator = arrayList.iterator();

        arrayList.add("abc");
        arrayList.add("def");

        //获取迭代器
        Iterator iterator = arrayList.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }


        //在迭代元素的过程中,不能调用集合对象的remove()方法
        Collection arrayList1 =new ArrayList();
        arrayList1.add(123);
        arrayList1.add(456);
        arrayList1.add(789);
        /*//迭代
        Iterator iterator1 = arrayList1.iterator();
        while(iterator1.hasNext()){
            System.out.println(iterator1.next());
            //ConcurrentModificationException
            //arrayList1.remove(123);
        }*/

        //解决办法:
        Iterator iterator1 = arrayList1.iterator();
        while (iterator1.hasNext()){
            Object object = iterator1.next();
            //iterator1.remove(456);//直接通过集合删除元素,没有通知迭代器(导致迭代器的快照和元集合状态不同)
            iterator1.remove();//删除的一定是当前元素
            System.out.println(object);
        }

        System.out.println(arrayList1.size());//0 删除干净了
    }
}

二.泛型

泛型的优点:
* 第一:集合中存储的元素更加统一
* 第二:从集合中取出的元素是泛型指定的类型,不需要进行大量的“向下转型”
*
* 缺点:
* 导致集合中存储的元素缺乏多样性
*
* 实际开发中,其实主要是同一种类型
*
* 但是如果是子类的特有方法,还是要向下转型

2.1 泛型的基础语法

public class GenericTest01 {
    public static void main(String[] args) {
        Animal animal =new Animal();
        Bird bird =new Bird();
        Cat cat =new Cat();

        //使用了泛型,那么 arrayList 这个集合只能放 Animal 类的元素
        Collection<Animal> arrayList = new ArrayList<Animal>();
        arrayList.add(animal);
        arrayList.add(bird);
        arrayList.add(cat);

        //arrayList.add("123");报错

        //迭代
        //记住这里也要泛型,表示迭代器迭代的是Animal类型
        Iterator<Animal> iterator = arrayList.iterator();
        while(iterator.hasNext()){
            iterator.next().move();
        }
        /*Animal is moving
          Bird is moving
          Cat is moving
          */
    }
}

class Animal{
    public  void move(){
        System.out.println("Animal is moving");
    }
}

class Cat extends Animal{

    @Override
    public void move() {
        System.out.println("Cat is moving");
    }

    public void catMouse(){
        System.out.println("猫抓老鼠!!!");
    }
}

class Bird extends Animal{
    @Override
    public void move() {
        System.out.println("Bird is moving");
    }

    public void fly(){
        System.out.println("鸟儿在飞翔!!!");
    }
}

2.2泛型的自动类型推断机制(钻石表达式)


import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class GenericTest02 {
    public static void main(String[] args) {
        //ArrayList<这里的类型会只动推断>,JDK8之后才允许
        //自动类型推断
        Collection<Animal> arrayList = new ArrayList<>();

        arrayList.add(new Animal());
        arrayList.add(new Cat());
        arrayList.add(new Bird());

        //迭代
        Iterator<Animal> iterator =arrayList.iterator();
        while(iterator.hasNext()){
            iterator.next().move();
        }
        /*Animal is moving
         Cat is moving
         Bird is moving
         */
    }
}

2.3 自定义泛型

/*
* 自定义泛型
*       <   > 里面是一个标识符
*       java中经常出现是
*       <E>和<T>
        E是Element首字母
        T是Typ首字母
* */
public class GenericTest03 <E>{

    public void dosome(E abc){
        System.out.println("dosome ...");
    }

    public static void main(String[] args) {
        GenericTest03<String> genericTest03 =new GenericTest03<>();
        genericTest03.dosome("???");
        //genericTest03.dosome(123);只能是String类型

        GenericTest03<Integer> genericTest031 = new GenericTest03<>();
        genericTest031.dosome(123);
    }
}

三.增强For循环

//JDK5.0之后推出了一个新特性:增强for循环,或者叫for each
//缺点:没下标,在需要使用下标的时候不建议使用增强for循环
public class ForEachTest01 {
    public static void main(String[] args) {
        //创建数组
        int[] array = {1,2,3,4,5};
        //创建集合
        Collection arrayList =new ArrayList();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        arrayList.add(4);
        arrayList.add(5);

        //遍历数组
        for (int i:array){
            System.out.print(i + " ");
        }

        System.out.println();
        
        //遍历集合
        for (Object o : arrayList){
            System.out.print(o + " ");
        }
    }
}

四.List接口

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

/*
 * 测试list接口常用方法
 *   1.list集合存储元素特点:有序可重复
 *      有序:list集合元素有下标
 *       从零开始以一递增
 *       可重复:存储了一个1还可以再存储一个1
 *   2.list既是Collection接口的子接口,那么肯定有list接口自己的特有的方法
 *    以下只列出list接口常见特有的方法:
 *    void add(int index, Object element)    在列表的指定位置插入指定元素(可选操作)。
 *    Object get(int index) 返回列表中指定位置的元素
 *    int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
 *    int lastIndexOf(Object o) 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
 *    Object remove(int index) 移除列表中指定位置的元素(可选操作)
 *    Object set(int index, E element) 用指定元素替换列表中指定位置的元素(可选操作)。
 * */
public class ListTest {
    public static void main(String[] args) {
        //创建集合对象
        List linkedList= new LinkedList();
        List vector= new Vector();
        List arrayList = new ArrayList();

        //添加元素
        arrayList.add("A");//默认添加到最后一项
        arrayList.add("B");//默认添加到最后一项
        arrayList.add("D");//默认添加到最后一项

        //void add(int index, Object element)    在列表的指定位置插入指定元素(可选操作)。
        arrayList.add(2,"C"); // 添加到指定位置

        //Object get(int index) 返回列表中指定位置的元素
        System.out.println(arrayList.get(3));//D

        /*
        * int indexOf(Object o) 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
        * int lastIndexOf(Object o) 返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
        * */
        arrayList.add("D");
        arrayList.add("C");
        arrayList.add("B");
        arrayList.add("A");
        System.out.println(arrayList.indexOf("A"));//0
        System.out.println(arrayList.indexOf("F"));//-1
        System.out.println(arrayList.lastIndexOf("A"));//7
        System.out.println(arrayList.lastIndexOf("F"));//-1

        //Object remove(int index) 移除列表中指定位置的元素(可选操作)
        arrayList.remove(0);
        //Collection 还有remove(Object o)方法,删除元素
        System.out.println(arrayList.get(0));//B   A被删除了


        //Object set(int index, E element) 用指定元素替换列表中指定位置的元素(可选操作)。
        for (Object o : arrayList){
            System.out.print(o + " ");//B C D D C B A
        }
        arrayList.set(0,"A");
        System.out.println();

        for (Object o : arrayList){
            System.out.print(o + " ");//A C D D C B A
        }
    }
}

五.ArrayList集合

public class ArrayListTest01 {
    public static void main(String[] args) {
        //构造方法
        //默认容量是10
        ArrayList arrayList1 =new ArrayList();
        ////指定初始化容量
        ArrayList arrayList2 =new ArrayList(100);

        //public ArrayList(Collection c)
        // 构造一个包含指定 collection 的元素的列表
        // 这些元素是按照该 collection 的迭代器返回它们的顺序排列的。
        //创建一个HashSet集合
        Collection hashSet= new HashSet();
        hashSet.add(1);
        hashSet.add(2);
        hashSet.add(3);
        ArrayList arrayList =new ArrayList(hashSet);
        //遍历
        for (int i = 0; i <arrayList.size() ; i++) {
            System.out.print(arrayList.get(i) + " ");//1 2 3
        }
    }
}

六.LinkedList集合

6.1 模拟单向链表

//模拟单链表
//链表的基本单元的Node
//对于单向链表来说:Node中存储了当前节点的数据,以及下一节点的内存地址
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 heard = null;

    //size
    int size = 0;
    public int size(){
        return this.size;
    }

    //向链表末尾中添加元素
    public void add(Object o){
        //判断是否是头文件
        if (heard == null){
            heard = new Node(o,null);
        }else{
            //头不是空
            //找出当时的末尾节点
            Node currentNode = findCurrentNode(heard);
            currentNode = new Node(o,null);
        }
        size ++;
    }

    /**
     *
     * @param node 起始节点
     * @return     末尾节点
     */
    public Node findCurrentNode(Node node) {
        //递归
        if (node.next == null){
            return node;
        }else {
            return findCurrentNode(node.next);
        }
    }
}

public class LinkTest {
    public static void main(String[] args) {
        Link myLink = new Link();
        myLink.add(1);
        myLink.add(2);
        myLink.add(3);
        myLink.add(4);
        myLink.add(5);
        //元素个数
        System.out.println(myLink.size);
    }
}

6.2 LinkedList

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/*
 * 链表的优点:
 *   由于链表上的元素在空间上的内存地址不连续
 *   因为随机增删的时候不会有大量的元素位移,因此随机增删效率较高
 *   在以后的开发中,如果遇到随机增删集合中的元素业务较多时,建议使用LinkedList
 * */
public class LinkedListTest {
    public static void main(String[] args) {
        //创建一个LinkedList对象
        List linkedList= new LinkedList();
        //添加元素
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        linkedList.add(4);
        linkedList.add(5);
        //遍历
        //for each
        for(Object o:linkedList){
            System.out.print(o + " ");
        }
        System.out.println();

        //迭代器迭代
        Iterator iterator = linkedList.iterator();
        while(iterator.hasNext()){
            System.out.print(iterator.next() + " ");
        }
        System.out.println();

        ////LinkedList集合底层也是有下标的
        //注意:ArrayList之所以检索效率高,不单是因为有下标,主要是底层是数组的原因
        //LikedList集合照样有下标,但是检索/查找效率某个元素效率比较低,因为只能从头节点开始一个一个遍历
        //下标循环
        for (int i = 0; i <linkedList.size() ; i++) {
            System.out.print(linkedList.get(i) + " ");
        }

        //LinkedList集合有初始化吗?没有
        //最初这个链表中没有任何元素,first和last引用都是null
        //不管是LikedList还是ArrayList,以后写代码不需要关系具体是哪个
        //因为我们要面向接口编程,调用的方法都是接口中的方法

        //List list2 = new ArrayList();//这样写表示调用了数组
        List list2 = new LinkedList();//这样写表示底层调用了双向链表
        list2.add("123");
        list2.add("456");
        list2.add("789");
        for (int i = 0; i < list2.size(); i++) {
            System.out.println(list2.get(i));
        }
    }
}

七.Vector集合

import java.util.*;

/*
 * Vector:
 *   1.底层也是一个数组
 *   2.初始化容量:10
 *   3.扩容之后是原来的二倍
 *     ArrayList是原来的1.5倍
 *   4.Vector的方法都带 synchronized 关键字,线程安全,效率较低
 *   6.怎么将一个线程不安全的ArrayList转换成线程安全的Vector?
 *       使用集合工具类:
 *           Java.util.Collections
 *
 *           java.util.Collection是集合接口
 *           java.util.Collections是集合工具类
 * */
public class VectorTest{
    public static void main(String[] args) {
        //多态
        Collection vector= new Vector();
        //添加元素
        vector.add(1);
        vector.add(2);
        vector.add(3);
        vector.add(4);
        vector.add(5);
        //遍历/迭代
        Iterator iterator =vector.iterator();
        while(iterator.hasNext()){
            System.out.print(iterator.next() + " ");
        }

        //Vector 是线程安全的
        //ArrayList不是线程安全的
        //怎么将ArrayList变成线程安全的呢?
        List arrayList = new ArrayList();
        //集合工具类
        Collections.synchronizedList(arrayList);
        //现在 arrayList 是线程安全的了
    }
}

八.Set接口

import java.util.HashSet;
import java.util.Set;

public class SetTest {
    public static void main(String[] args) {
        //Set是Collection的子接口,不能new set对象
        //'Set' is abstract; cannot be instantiated
        //Set set =new Set();
        Set hashSet= new HashSet();
    }
}

九.HashSet集合


import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/*
 * HashSet集合:
 *   无序不可重复
 * */
public class HashSetTest {
    public static void main(String[] args) {
        Set<Integer> hashSet = new HashSet<>();
        hashSet.add(3);
        hashSet.add(1);
        hashSet.add(2);
        hashSet.add(5);
        hashSet.add(8);
        hashSet.add(4);
        hashSet.add(3);
        hashSet.add(1);
        hashSet.add(3);
        //遍历
        Iterator iterator= hashSet.iterator();
        while(iterator.hasNext()){
            System.out.print(iterator.next() + " " );
        }
    }
}

十.TreeSet集合

10.1 TreeSet集合的基础语法


import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

/*
 * TreeSet集合存储元素特点:
 *   1.无序不可重复,但是存储的元素可以自动按照大小排序
 *   称为:可排序集合
 *   2.无序:这里的无序是指存进去的顺序和取出来的顺序不同,且没有下标
 *   3.TreeSet底层实际上是一个TreeMap
 *   4.TreeMap底层是一个二叉树
 *   5.放到TreeSet集合里的元素,等同于放到TreeMap集合的key里面
 *   6.TreeSet集合中的元素:无序不可重复,但是按着元素的大小排序
 *   称为:可排序集合*/
public class TreeSetTest01 {
    public static void main(String[] args) {
        Set treeSet= new TreeSet<>();
        treeSet.add(10);
        treeSet.add(5);
        treeSet.add(20);
        treeSet.add(1);
        //迭代
        Iterator iterator =treeSet.iterator();
        while(iterator.hasNext()){
            System.out.print(iterator.next() + " ");//1 5 10 20 排序了
        }

        System.out.println();

        treeSet.clear();
        treeSet.add("A");
        treeSet.add("Z");
        treeSet.add("B");
        treeSet.add("F");
        treeSet.add("D");
        treeSet.add("H");
        for (Object o :treeSet){
            System.out.print(o + " ");//A B D F H Z  小到大的排序
        }
    }
}

10.2 自定义类在TreeSet里怎么排序
第一种方法:

`import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

public class TreeSetTest03 {
    public static void main(String[] args) {
        //创建顾客对象
        Customer customer1 =new Customer(1);
        Customer customer2 =new Customer(2);
        Customer customer3 =new Customer(3);
        Customer customer4 =new Customer(4);
        Customer customer5 =new Customer(5);
        //创建TreeSet对象
        TreeSet<Customer> treeSet =new TreeSet<>();
        //添加元素
        treeSet.add(customer1);
        treeSet.add(customer2);
        treeSet.add(customer3);
        treeSet.add(customer4);
        treeSet.add(customer5);
        //迭代
        Iterator<Customer> iterator = treeSet.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        /*Customer{age=1}
          Customer{age=2}
          Customer{age=3}
          Customer{age=4}
          Customer{age=5}
          */
    }
}

//放在TreeSet集合中的元素要实现java.lang.Comparable接口
//并且实现compareTo方法,equals可以不重写
//这里要泛型,要不然下面会报错
class Customer implements Comparable<Customer>{
    int age;

    public Customer(){

    }

    public Customer(int age){
        this.age = age;
    }

    //需要在这个方法中编写比较的逻辑
    //k.compareTo(t.key)
    //拿着参数k和集合的每一个key比较,返回值可能是大于零,可能是小于零,可能是等于零
    //比较规则还是由程序员来定
    @Override
    public int compareTo(Customer c) {
        /*if (this.age == c.age){
            return 0;
        }else if (this.age >c.age){
            return 1;
        }else if (this.age < c.age){
            return 1;
        }*/
        return this.age -c.age;
    }

    //重写toString方法
    @Override
    public String toString() {
        return "Customer{" +
                "age=" + age +
                '}';
    }
}
`

import java.util.TreeSet;

public class TreeSetTest04 {
    public static void main(String[] args) {
        //创建Vip对象
        Vip vip1 =new Vip(10,"A");
        Vip vip2 =new Vip(20,"A");
        Vip vip3 =new Vip(10,"Z");
        Vip vip4 =new Vip(30,"Z");
        Vip vip5 =new Vip(15,"D");
        //创建集合对象
        TreeSet<Vip> treeSet =new TreeSet<>();
        //添加元素
        treeSet.add(vip1);
        treeSet.add(vip2);
        treeSet.add(vip3);
        treeSet.add(vip4);
        treeSet.add(vip5);
        //遍历
        for (Vip vip : treeSet){
            System.out.println(vip);
        }
        /*Vip{age=10, name='A'}
              Vip{age=10, name='Z'}
              Vip{age=15, name='D'}
              Vip{age=20, name='A'}
              Vip{age=30, name='Z'}
         */
    }
}

//先按照年龄升序,如果年龄一样在按着姓名升序
class Vip implements Comparable<Vip>{
    private int age;
    private String name;

    //构造方法
    public Vip() {

    }

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

    //实现 compareTo 方法
    @Override
    public int compareTo(Vip o) {
        if (this.age == o.age){
            //String类实现了 compareTo 方法
            return this.name.compareTo(o.name);
        }else {
            return this.age - o.age;
        }
    }

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

第二种方法:


import java.util.Comparator;
import java.util.TreeSet;

//TreeSet集合元素可排序的第二种方式:使用比较器的方式
/*放到TreeSet或者TreeMap集合key部分的元素想要做到排序,有两种方式:
 *       第一种:放在集合中的元素实现 java.lang.Comparable接口
 *       第二种:在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象。
 * Comparable和Comparator怎么选择?
 * 如果比较规则一直不变的话,或者比较规则只有一个:Comparable
 * 如果比较规则经常改变的话,或者比较规则有多个  :Comparator*/
public class TreeSetTest05 {
    public static void main(String[] args) {
        //给构造方法传一个比较器
        //TreeSet<AnimalTest> testTreeSet = new TreeSet<>(new AnimalTestComparator());

        //或者用匿名内部类
        TreeSet<AnimalTest> testTreeSet = new TreeSet<>(new Comparator<AnimalTest>() {
            @Override
            public int compare(AnimalTest o1, AnimalTest o2) {
                return o1.getNo() - o2.getNo();
            }
        });
        //创建AnimalTest对象
        AnimalTest animalTest1 =new AnimalTest(10);
        AnimalTest animalTest2 =new AnimalTest(5);
        AnimalTest animalTest3 =new AnimalTest(15);
        AnimalTest animalTest4 =new AnimalTest(1);
        AnimalTest animalTest5 =new AnimalTest(20);
        //添加元素
        testTreeSet.add(animalTest1);
        testTreeSet.add(animalTest2);
        testTreeSet.add(animalTest3);
        testTreeSet.add(animalTest4);
        testTreeSet.add(animalTest5);
        for (AnimalTest a:testTreeSet){
            System.out.println(a);
        }
        /*AnimalTest{no=1}
          AnimalTest{no=5}
          AnimalTest{no=10}
          AnimalTest{no=15}
          AnimalTest{no=20}
          */
    }
}
class AnimalTest{
    private int no;

    public AnimalTest() {

    }

    public AnimalTest(int no) {
        this.no = no;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    @Override
    public String toString() {
        return "AnimalTest{" +
                "no=" + no +
                '}';
    }
}

/*
//单独编写一个比较器
//比较器实现java.util.Comparator接口。(Comparable是java.lang包下的)
class AnimalTestComparator implements Comparator<AnimalTest>{

    @Override
    //比较方法
    public int compare(AnimalTest o1, AnimalTest o2) {
        return o1.getNo() - o2.getNo();
    }


}*/

十一.Map接口

11.1 Map集合的常用方法

/*
* java.util.Map接口中常用的方法:
*   1.Map和Collection没有继承关系
*   2.Map集合以key和value的方式存储数据:键值对
*       key和value都是引用数据类型
*       key和value都是存储对象的内存地址
*       key起主导作用,value是key的一个附属品
*   3.Map集合中常用方法
        V put(K key, V value)   向Map集合中添加键值对
        V get(Object key)       通过key获取value
        void clear()            清空Map集合
        boolean containsKey(Object key)   判断Map集合中是否包含某个key
        boolean containsValue(Object value) 判断Map集合中是否包含某个Value
        boolean isEmpty()               判断Map结合中的元素个数是否为零
        Set<K> keySet()                 获取Map集合中所有的key(所有的键是一个set集合)
        V remove(Object key)            通过key删除Value
        int size()                      获取Map集合中键值对的个数
         Collection<V> values()         获取Map集合中所有的value,返回一个Collection
        Set<Map.Entry<K,V>> entrySet()  将Map集合转化成Set集合
        *
 */
public class MapTest01 {
    public static void main(String[] args) {
        //Map 也是一个接口
        //'Map' is abstract; cannot be instantiated
        //Map map =new Map();

        //泛型,创建集合对象
        Map<Integer,String> hashMap= new HashMap<>();
        //向集合中添加元素
        //V put(K key, V value)   向Map集合中添加键值对
        hashMap.put(1,"钢铁侠");//1 在这自动装箱了
        hashMap.put(2,"雷神");
        hashMap.put(3,"美队");
        hashMap.put(4,"绿巨人");

        //boolean containsKey(Object key)   判断Map集合中是否包含某个key
        System.out.println(hashMap.containsKey(1));//true
        System.out.println(hashMap.containsKey(10));//false



        //boolean containsValue(Object value) 判断Map集合中是否包含某个Value
        System.out.println(hashMap.containsValue("钢铁侠"));//true
        System.out.println(hashMap.containsValue("蜘蛛侠"));//false



        //Set<K> keySet()      获取Map集合中所有的key(所有的键是一个set集合)
        Set set = hashMap.keySet();
        System.out.println(set.size());//4
        //遍历这个set集合
        for (Object o : set) {
            System.out.println(set);
            /*[1, 2, 3, 4]
              [1, 2, 3, 4]
              [1, 2, 3, 4]
              [1, 2, 3, 4]
             */
        }



        //Collection<V> values()         获取Map集合中所有的value,返回一个Collection
        Collection c = hashMap.values();
        //遍历集合
        Iterator iterator =c.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        /*钢铁侠
          雷神
          美队
          绿巨人
        */


        //Set<Map.Entry<K,V>> entrySet()  将Map集合转化成Set集合
        Set set1 = hashMap.entrySet();
        System.out.println(set.size());//4
        //遍历这个set集合
        for (Object o : set) {
            System.out.println(set1);
        }
        /*[1=钢铁侠, 2=雷神, 3=美队, 4=绿巨人]
          [1=钢铁侠, 2=雷神, 3=美队, 4=绿巨人]
          [1=钢铁侠, 2=雷神, 3=美队, 4=绿巨人]
          [1=钢铁侠, 2=雷神, 3=美队, 4=绿巨人]
        */


        // V get(Object key)     通过key获取value
        System.out.println(hashMap.get(1));//钢铁侠
        System.out.println(hashMap.get(2));//雷神



        //int size()        获取Map集合中键值对的个数
        System.out.println(hashMap.size());//4



        //V remove(Object key)            通过key删除Value
        hashMap.remove(1);
        System.out.println(hashMap.size());//3
        System.out.println(hashMap.containsKey(1));//false



        //boolean isEmpty()               判断Map结合中的元素个数是否为零
        System.out.println(hashMap.isEmpty());//false



        //void clear()       清空Map集合
        hashMap.clear();
        System.out.println(hashMap.isEmpty());//true
    }
}


11.2 Map集合的遍历

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/*
Map集合的遍历(非常重要)
*/
public class MapTest02 {
    public static void main(String[] args) {
        Map<Integer,String> hashMap = new HashMap<>();
        hashMap.put(1,"钢铁侠");//1 在这自动装箱了
        hashMap.put(2,"雷神");
        hashMap.put(3,"美队");
        hashMap.put(4,"绿巨人");

        //第一种方式:获取所有的key,遍历key,来遍历所有的value
        //先获取所有的key,所有的key是一个Set集合
        Set<Integer> hashSet= hashMap.keySet();
        //可以用迭代器
        Iterator iterator = hashSet.iterator();
        while(iterator.hasNext()){
            Object o = iterator.next();
            String s =hashMap.get(o);
            System.out.println(s);
        }

        System.out.println("================================");

        //还可以用for each 循环
        for(Object o : hashSet){
            System.out.println(hashMap.get(o));
        }

        System.out.println("================================");


        //第二种方式
        //Set<Map.Entry<K,V>> entrySet()  将Map集合转化成Set集合
        //Set集合中元素的类型是: Map.Entry
        Set<Map.Entry<Integer,String>> set = hashMap.entrySet();
        //遍历Set集合,每一次取出一个Node

        //可以用迭代器迭代
        Iterator<Map.Entry<Integer,String>> iterator1 = set.iterator();
        while(iterator1.hasNext()){
            Map.Entry<Integer,String> entry = iterator1.next();
            Integer key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + " = " + value);
        }

        System.out.println("================================");

        for (Map.Entry<Integer,String> node : set){
            System.out.println(node.getKey() + " = " + node.getValue());
        }
    }
}

十二.HashMap集合

12.1 HashMap中get和put方法


import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/*
* HashMap集合:
*   1.HashMap集合底层是哈希表/散列表的数据结构
*   2.哈希表是一个数组和单向链表的结合体
*       数组:在查询方面效率很高
*       单向链表:在随机增删方面效率很高
*       哈希表将以上两种数据结构融合在一起了,充分发挥了他们各自的优点
*   3.HashMap底层代码:
*       public class HashMap{
*
*               //HashMap底层实际上是一个数组(一维数组)
*               transient Node<K,V>[] table;
 *
 *              //静态内部类HashMap.Node
 *              static class Node<K,V> implements Map.Entry<K,V>{
                    final int hash;//哈希值(哈希值是key的hashCode()方法执行的结果,hash值通过哈希函数/算法,可以转化成数组的数组的下标)
                    final K key;    //Map集合的key
                    V value;        //Map集合的value
                    Node<K,V> next;//下一个节点的内存地址
 * }
 *
 *
 *      哈希表/散列表:一维数组,这个数组里面的每一个元素是一个单向列表(数组和链表的结合体)
 *
 *      4.最主要掌握:
 *          map.put(key,value)
 *          value = map.get(k)
 *          这两个方法的原理
*
*       5.HashMap集合的key部分特点:
*           无序不可重复
*           无序? 因为不一定挂在哪个单向链上
*           不可重复?equals方法来保证HasMap集合的key不可重复
*           如归key重复了,value会被覆盖
*
*                   放在HashSet的元素实际上是放到了HashMap的集合key部分中了
*                       所以HashSet也要重写equals和HashCode
*       6.HashMap使用不当时无法发挥性能
*           假设将所有的HashCode()方法返回固定值,那么就会导致底层哈希表变成纯单向链表
*               称为   散列分布不均匀
* *           假设将所有的HashCode()方法返回不同值,那么就会导致底层哈希表变成一维数组
                    也是  散列分布不均匀
                    散列分布均匀  需要重写HashCode()有技巧
         7.重点:
            放在HashMap集合中key部分的元素,以及放在HashSet中的元素,需要重写HashCode和equal方法

          8.HashMap集合的默认容量是16,默认加载因子是0.75
          *         这个默认加载因子是当HashSet集合底层数组容量达到75%时开始扩容
          * 重点:HashMap集合初始化容量必须是2的倍数,这是官方推荐的
          *     这是因为达到散列分布均匀,为了提高HashMap集合的存取效率所必须的
           */
public class HashMapTest01 {
    public static void main(String[] args) {
        //测试HashMap集合key部分元素特点
        //Integer是key,它的HashCode和equals方法都已经重写了
        Map<Integer,String> hashMap= new HashMap<>();
        hashMap.put(1,"钢铁侠");//1 在这自动装箱了
        hashMap.put(2,"雷神");
        hashMap.put(3,"美队");
        hashMap.put(3,"绿巨人");

        System.out.println(hashMap.size());//3
        //遍历
        Set<Map.Entry<Integer,String>> set = hashMap.entrySet();
        Iterator<Map.Entry<Integer,String>> iterator = set.iterator();
        while(iterator.hasNext()){
            Map.Entry<Integer,String> entry = iterator.next();
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
        //可知,原来的美队被覆盖了
        /*1 = 钢铁侠
          2 = 雷神
          3 = 绿巨人
          */
    }
}

12.2 自定义类在HashMap中get和put


import java.util.HashMap;
import java.util.HashSet;
import java.util.Objects;

/*1.  向Map集合中 存和取  都是先调用key的HashCode方法,然后再调用equals方法
 * equals方法可能调用,可能不调用
 *   拿put(k,v)举例,什么时候不调用equals
 *       k.HashCode()方法返回哈希值,
 *           哈希值是经过哈希算法得出数组下标
 *           数组下标位置上如果是null,就不会调用equals
 *
 *   拿get(k)举例,什么时候不调用equals
 *       哈希值是经过哈希算法得出数组下标
 *           数组下标位置上如果是null,就不会调用equals
 *
 * 2. 注意:如果一个类的equals方法重写了,那么hashCode()必须重写
 * 并且equals方法返回如果是true,呢么hashcode返回值必须一样
 *  equals方法返回true表示两个对象相同,在同一个单向链表上
 *  对于同一个单向链表的节点来说,他们的哈希值都相同
 *  使用hashCode的返回值也要是true
 *
 * 3.hashCode和equals直接用idea生成
 *
 *结论:
 *  放在HashMap集合key部分和HashSet集合中的元素,要同时重写hashCode和equals方法
 * */
public class HashMapTest02 {
    public static void main(String[] args) {
        People people1 =new People("钢铁侠",123);
        People people2 =new People("钢铁侠",123);

        //重写equals方法和hashCode方法之前
        System.out.println(people1.equals(people2));//false
        System.out.println(people1.hashCode());//1809787067
        System.out.println(people2.hashCode());//1802598046

        //重写equals,没重写hashCode
        System.out.println(people1.equals(people2));//true

        //HashSet存储在HashMap的key部分
        HashSet<People> hashSet = new HashSet<>();
        hashSet.add(people1);
        hashSet.add(people2);
        //按理来说,这两个对象equals返回true,应该是重复了,而HashSet集合无序不可重复
        //应该只有一个元素
        System.out.println(hashSet.size());//2
        //这是因为这两个元素的 hash值不同,所以存储在数组的位置不同
        //因此我们要重写hashCode方法
        System.out.println(people1.hashCode());//1170776379
        System.out.println(people2.hashCode());//1170776379
        System.out.println(hashSet.size());//1
    }
}

class People{
    //属性
    private String name;
    private int no;

    //构造方法
    public People() {
    }

    public People(String name, int no) {
        this.name = name;
        this.no = no;
    }

    public String getName() {
        return name;
    }

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

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        People people = (People) o;
        return no == people.no &&
                Objects.equals(name, people.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, no);
    }
}

十三.Hashtable集合

Hashtable是线程安全的,底层也是哈希表

十四.Properties集合

import java.util.Properties;

/*
 * 目前只需要掌握Properties属性类的相关方法
 * Properties是一个Map集合,继承HashTable,Properties的key和value都是String类型的
 * Properties被称为属性类对象
 * Properties是线程安全的
 * */
public class PropertiesTest {
    public static void main(String[] args) {
        Properties properties =new Properties();

        //Properties需要掌握两个方法,一个存一个取
        properties.setProperty("123","钢铁侠");
        properties.setProperty("456","蜘蛛侠");

        System.out.println(properties.getProperty("123"));//钢铁侠
        System.out.println(properties.getProperty("456"));//蜘蛛侠
    }
}

十五.TreeMap集合

TreeMap底层是二叉树
TreeMap集合的key可以自动按照大小顺序排序。

总结(所有的实现类):

ArrayList:底层是数组。
LinkedList:底层是双向链表。
Vector:底层是数组,线程安全的,效率较低,使用较少。
HashSet:底层是HashMap,放到HashSet集合中的元素等同于放到HashMap集合key部分了。
TreeSet:底层是TreeMap,放到TreeSet集合中的元素等同于放到TreeMap集合key部分了。
HashMap:底层是哈希表。
Hashtable:底层也是哈希表,只不过线程安全的,效率较低,使用较少。
Properties:是线程安全的,并且key和value只能存储字符串String。
TreeMap:底层是二叉树。TreeMap集合的key可以自动按照大小顺序排序。

List集合存储元素的特点:
有序可重复
有序:存进去的顺序和取出的顺序相同,每一个元素都有下标。
可重复:存进去1,可以再存储一个1.

Set(Map)集合存储元素的特点:
无序不可重复
无序:存进去的顺序和取出的顺序不一定相同。另外Set集合中元素没有下标。
不可重复:存进去1,不能再存储1了。

SortedSet(SortedMap)集合存储元素特点:
首先是无序不可重复的,但是SortedSet集合中的元素是可排序的。
无序:存进去的顺序和取出的顺序不一定相同。另外Set集合中元素没有下标。
不可重复:存进去1,不能再存储1了。
可排序:可以按照大小顺序排列。

Map集合的key,就是一个Set集合。
往Set集合中放数据,实际上放到了Map集合的key部分。


转载:https://blog.csdn.net/Destiny_159/article/details/105467943
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场