20200327Java学习笔记:集合

集合

  1. 集合本身是一个对象,一个容器,它用来存储对象的引用也就是对象的地址,不存储对象本身和基本数据类型。

  2. Java中每一个不同的集合,底层对应了不同的数据结构。在不同的集合中存储元素,等于数据放到了不同的数据结构中。

    常见的数据结构:数组、二叉树、链表、哈希表等。例如ArrayLIst()底层是数组,LinkedList()底层是链表。不同数据结构的存储方式不一样。

    Java中已经实现了数据结构,只需要学会合理使用。

  3. 所有的集合类和集合接口都在java.util包下。

  4. Java中集合分为两类:一类是单个方式存储元素,它的超级父接口是Collection;一类是以键值对(键和值一一对应)的方式存储元素,它的超级父接口是Map。

  5. 掌握集合的继承结构图。泛化关系就是继承关系。

    单个方式存储元素的继承结构图

在这里插入图片描述

键值对的继承结构图

总结所有实现类:

  • ArrayList:底层是数组。
  • LinkedList:底层是双向链表。对于链表数据结构来说,随机增删效率高,检索效率低,内存地址不连续。
  • Vector:底层是数组,线程安全,效率较低,使用较少。
  • HashSet:底层是HashMap,放到HashSet集合中等同于放到HashMap的key部分。
  • TreeSet:底层是TreeMap,放到TreeMap集合中的元素等同于放到TreeMap集合key部分。
  • HashMap:底层是哈希表。
  • Hashtable:底层也是哈希表,只不过效率较低,使用较少,线程安全。
  • Properti:线程安全,并且key和value只能储存字符串。
  • TreeMap:底层是二叉树。TreeMap集合的key可以自动按照大小顺序排序。

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

Set集合存储元素特点:无序不可重复,存进去和取出来的顺序不一定相同,元素没有下标。

SortSet集合存储元素特点:由于继承了Set集合,所以它的特点也是无序不可重复。但是放在SortSet集合中的元素可以自动按照大小顺序排序。

放在集合中的元素是一定要重写equals方法的。

collec接口常用方法

常用方法简介

package Collection;

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

/*
Collection中常用方法
 */
public class Test01 {
    public static void main(String[] args) {
        //创建一个集合对象
        //Collection c=new  Collection; 接口是不能实例化的
        //多态,父类引用指向子类
        Collection c=new ArrayList();
        //测试Collection接口中的常用方法
        //add,往集合里加元素
        c.add(1200);//这里实际上存的是一个对象地址,自动装箱了。
        c.add(true);
        c.add(new Object());
        //获取集合中元素的个数
        System.out.println("集合中元素的个数是:"+c.size());

        //清空集合
        c.clear();
        System.out.println("集合中元素的个数是:"+c.size());//0

        //再添加元素
        c.add("hello");
        c.add("浩克");
        c.add(1);
        System.out.println("集合中元素的个数是:"+c.size());//3

        //判断集合中是否包含某一元素,输出一个布尔值
        boolean flag1=c.contains("hello");//true
        System.out.println(flag1);
        boolean flag2=c.contains("绿巨人");//false
        System.out.println(flag2);

        //删除集合中某一个元素
        c.remove(1);
        System.out.println("集合中元素的个数是:"+c.size());//2

        //判断集合是否为空,集合中是否存在元素
        System.out.println(c.isEmpty());//false
        c.clear();
        System.out.println(c.isEmpty());//true

        c.add("abc");
        c.add("def");
        c.add("100");
        c.add("HelloWorld!");

        //把集合转化为一个数组
        Object[]objects=c.toArray();
        //遍历数组
        for (Object o:objects) {
            System.out.println(o);
            //这里自动重写了,o.toString

        }

    }
}

迭代器的原理

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

package Collection;

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

//集合的遍历/迭代专题,重要指数*****
public class Test02 {
    public static void main(String[] args) {
        //注意:以下讲解的遍历方式、迭代方式,是所有Collection通用的一种方式
        //在Map集合中不能用,在所有的Collection以及子类中使用

        //创建集合对象
        Collection c=new ArrayList();//重点在前面Collection的接口,如何遍历
        //添加元素
        c.add("abc");
        c.add("def");
        c.add(100);
        c.add(new Object());
        //对集合进行遍历、迭代
        //第一步:获取集合对象的迭代器对象Iterator,迭代器是一个对象
        //因为Collection继承的Iterable接口中有iterator方法,所以可以调用,返回一个迭代器
        Iterator iterator=c.iterator();
        //第二步:通过以上获取的迭代器对象开始迭代、遍历集合(重要)
        /*
         迭代器对象Iterator中的两个方法
         boolean hasNext() 如果仍有元素可以迭代,返回true
         Object next()返回迭代的下一个元素
         */
        boolean hasNext=iterator.hasNext();
        while (iterator.hasNext()){
            //无论存进去是什么,取出来都是Object
            Object object=iterator.next();
            System.out.println(object);
        }

    }
}
/*=======================================================*/
package Collection;

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

/*
集合的迭代、遍历
 */
public class Test03 {
    public static void main(String[] args) {
        //创建集合对象
        Collection c1=new ArrayList();
        //添加元素
        c1.add(1);
        c1.add(2);
        c1.add(3);
        c1.add(4);

        //迭代集合
        Iterator it=c1.iterator();
        while (it.hasNext()){
           Object obj=it.next();
//           if(obj instanceof Integer){
//               System.out.println("Integer类型");
//           }
            //存进去什么类型取出来还是什么类型,只不过输出时转为了String
            //这里println会调用toString方法
            System.out.println(obj);
        }

        //HashSet集合,无序不可重复
        Collection c2=new HashSet();
        c2.add(100);
        c2.add(200);
        c2.add(300);
        c2.add(200);
        c2.add(400);
        c2.add(100);
        Iterator it2=c2.iterator();
        while (it2.hasNext()){
            System.out.println(it2.next());
            //存进去和取出来的顺序不一定相同,重复的元素不能存储
        }


    }
}


当集合的结构发生改变时,迭代器必须重新获取,否则会出现异常。

package Collection;

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

public class Test06 {
    public static void main(String[] args) {
        //创建集合,
        Collection c=new ArrayList();
       //此时获取的迭代器,指向的是集合中没有元素时的迭代器
       // Iterator iterator=c.iterator();
        // 一定要注意,集合结构发生改变,迭代器必须重新获取
        //否则会有异常Exception in thread "main" java.util.ConcurrentModificationException

        //添加元素
        c.add(1);
        c.add(2);
        c.add(3);

        //重新获取迭代器
        Iterator iterator=c.iterator();
        while(iterator.hasNext()){
            Object obj= iterator.next();
            System.out.println(obj);
        }
    }
}

contains方法

package Collection;

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

/*
深入集合的contains方法
boolean contains(Object o)
判断集合中是否包含某对象,如果包含返回true,不包含返回false

contains方法是用来判断集合中是否包含某个元素的,它在底层调用了equals方法进行比对。
 */
public class Test04 {
    public static void main(String[] args) {
        //创建集合对象
        Collection c=new ArrayList();

        //向集合里存储元素
        String s1=new String("abc");//0x111
        String s2=new String("def");//0x222
        c.add(s1);
        c.add(s2);

        //集合中元素个数
        System.out.println("集合中元素个数是:"+c.size());
        String x=new String("abc");//0x555

        System.out.println(c.contains(x));
        //返回是true,因为contains调用了equals方法
        //实际上是判断它集合中是否包含“abc”
    }
}

Collection接口中的remove方法和contains方法底层都会调用equals方法。放在集合中的元素要重写equals方法,重写比较的是内容,不重写比较的是地址。也就是说equals是需要重写的。

package Collection;

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

/*
测试contains方法
 */
public class Test05 {
    public static void main(String[] args) {
        Collection c=new ArrayList();

        User u1=new User("jack");
        User u2=new User("jack");

        c.add(u1);
        //判断集合是否包含u2
        System.out.println(c.contains(u2));
        /*
        在没有重写equals之前,这个结果是false。调用的是Object的equals方法,比较的是对象的地址
        在重写equals方法之后,就比较内容了。名字一样就不再比较内容了。
         */
    }

}
class User{
    private String name;
    public User(String name){
        this.name=name;
    }
    //重写equals方法,则调用重写的equals方法
    //这个equals方法比较的是内容
    public boolean equals(Object o){
        if(o==null||!(o instanceof User)) return false;
        if(o==this) return true;
        User u=(User)o;
        //如果名字一样,就不再比较对象的内存地址了。
        return u.name.equals(this.name);
    }
}

package Collection;

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

/*
测试remove方法
 */
public class Test05 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        //创建一个字符串
        String s1=new String ("hello");
        //字符串放进集合中
        c.add(s1);
        //创建一个新的字符串
        String s2=new String("hello");
        //删除s2
        c.remove(s2);
        //集合中元素个数
        System.out.println(c.size());//0

    }

}
class User{
    private String name;
    public User(String name){
        this.name=name;
    }
    //重写equals方法,则调用重写的equals方法
    //这个equals方法比较的是内容
//    public boolean equals(Object o){
//        if(o==null||!(o instanceof User)) return false;
//        if(o==this) return true;
//        User u=(User)o;
//        //如果名字一样,就不再比较对象的内存地址了。
//        return u.name.equals(this.name);
//    }

    //alt +ins 自动插入equals方法重写
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(name, user.name);
    }

}

在集合中删除元素

package Collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
//在迭代元素的过程中,一定要使用迭代器的remove()方法删除元素,不要使用集合自带的remove方法
public class Test06 {
    public static void main(String[] args) {
        //创建集合,
        Collection c=new ArrayList();

        //添加元素
        c.add(1);
        c.add(2);
        c.add(3);

        //重新获取迭代器
        Iterator iterator=c.iterator();
        while(iterator.hasNext()){
            Object obj= iterator.next();
            /*
       c.remove(obj);
       删除元素,删除之后集合的结构发生了改变,应该重新获取迭代器
       但是,循环下一次的时候并没有重新获取迭代器,所以会出现异常
        */
            iterator.remove();
            //删除的一定是迭代器指向的当前元素
            //使用迭代器删除,会更新迭代器和集合
            System.out.println(obj);
        }
        System.out.println(c.size());//0
    }
}

List接口常用方法

package List;

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

/*
List接口中常用方法
1.List集合存储元素特点:有序可重复,从0开始,以1递增。
   可重复存储相同元素。
2.List特色的方法:
    void add(int index,E element)
    Object get(int index)
    int indexOf(Object o)
    int LastIndexOf(Object o)
    Object remove(int index)
    Object set(int index, Object elment)
    现在以理解为主,开发时遇到再查找文档
 */
public class Test01 {
    public static void main(String[] args) {
        //List list=new LinkedList();
        List list=new ArrayList();

        //添加元素
        list.add("A");
        list.add("C");
        list.add("B");
        list.add("C");//向列表尾部添加元素
        //特有方法
        list.add(1,"King");//在指定位置添加元素,效率较低


        Iterator it=list.iterator();
        while (it.hasNext()){
            Object obj=it.next();
            System.out.println(obj);
        }
        //根据下标获取元素
//        Object obj=list.get(0);
//        System.out.println(obj);
        //因为有下标,所以List集合有自己比较特殊的遍历方式,通过下标遍历
        for (int i=0;i<list.size();i++){
            Object obj=list.get(i);
            System.out.println(obj);
        }

        //获取指定对象第一次出现处的索引。
        System.out.println(list.indexOf("King"));//1

        //获取指定对象最后一次出现处的索引
        System.out.println(list.lastIndexOf("C"));//4

        //删除指定下标位置的元素
         list.remove(1);

        //修改指定位置的元素
        list.set(2,"queen");

        for (int i=0;i<list.size();i++){
            Object obj=list.get(i);
            System.out.println(obj);
        }

    }
}

ArrayList实现类

package Collection.List;

import java.util.ArrayList;
import java.util.List;

/*
ArrayLIst集合:
    1.初始化容量为10,底层先创建了一个长度为0的数组,当添加第一个元素时,初始化容量为10
    2.集合底层是一个Object[]数组
    3.构造方法
    new ArrayList();
    new ArrayList(20);
    4.ArrayList集合的扩容:原容量的1.5倍
    ArrayList底层是数组,扩容效率低,建议在使用时预估计元素个数
    这是比较重要的优化策略
    5.数组优点:检索效率比较高
    6.数组缺点:随机增删元素效率比较低,
               无法存储大数据量
    7.向数组末尾添加元素,效率很高,不受影响

 */
public class ArrayListTest01 {
    public static void main(String[] args) {
        //默认初始化容量是10
        List list1=new ArrayList();
        //指定容量为20
        List list2=new ArrayList(20);
        //size()方法获取的是当前集合中元素的个数,不是集合的容量。
        System.out.println(list2.size());//0


    }
}

把线程安全的变成线程非安全的

 List list1=new ArrayList();//线程非安全的
        
 Collections.synchronizedList(list1);//变成线程安全的

ArrayList的构造方法

package Collection.List;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

/*
集合ArrayList的构造方法
 */
public class ArrayListTest02 {
    public static void main(String[] args) {
        List list1=new ArrayList();
        //指定初始化容量100
        List list2=new ArrayList(100);

        //创建一个HashSet集合
        Collection c=new HashSet();
        c.add(100);
        c.add(200);
        c.add(300);

        //把c作为参数传入
        //通过这个构造方法,就可以将HashSet转换成List集合
        List list3=new ArrayList(c);
    }
}

单向列表的数据结构

对于链表数据结构来说,基本的单元节点是Node,对于单向链表来说,任何一个节点Node中都有两个属性:第一,存储的数据;第二,下一个节点的内存地址。

在这里插入图片描述

链表的优点和缺点:

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

链表缺点:查询效率较低,每一次查询某个元素的时候都需要从头节点开始往下遍历。

package Collection.List;

import java.util.LinkedList;
import java.util.List;
/*
链表的优点:
    由于链表上的元素在空间存储上内存地址不连续,所以随机增删元素的时候不会有大量元素位移
    因此随机增删效率较高
    在以后的开发中,如果遇到随机增删集合元素情况较多,建议使用LinkedList
链表的缺点:
    每一次查找元素,都是从头开始遍历,直到找到为止,所以LinkedList查找效率较低。
    ArrayList:具有检索优势,但是线程不安全。
    LinkedList:具有随机增删优势。
    但是添加元素一般都从末尾添加。所以ArrayList用的多
 */
public class LinkedListTest01 {
    public static void main(String[] args) {
        //LinkedList集合底层也有下标
        //ArrayList之所以检索效率高是因为底层数组发挥的作用
        //LinkedList集合照样有下标,但是检索效率比较低,因为只能从头节点开始遍历
        List list=new LinkedList();

        list.add("a");
        list.add("b");
        list.add("c");

        for (int i=0;i<list.size();i++){
            Object object=list.get(i);
            System.out.println(object);
        }
		// LinkedList集合中没有初始化容量
        // 最初这个链表中没有没有任何元素。first和last引用都是null
    }
}

双向链表:LinkedList

双向链表的基本单元还是Node,

节点包含三个部分:上一个节点的内存地址,数据,下一个节点的内存地址。

在这里插入图片描述

对于数据结构,不需要深入理解,掌握方法就可以开发。

泛型

大多数情况下,集合中元素类型中元素类型是统一的,需要使用泛型

package Collection.Generic;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/*
泛型这种语法机构,主要是在编译阶段起作用,给编译器看。
使用泛型的好处是,集合中存储的元素类型同一,从集合中取出的类型是泛型制定的类型。
泛型的缺点:导致集合中存储的元素缺乏多样性。
大多数情况下,集合中元素类型中元素类型是统一的,需要使用泛型
 */
public class Test {
    public static void main(String[] args) {
        //使用泛型List<Animal> 之后,表示List集合中只允许存储Animal类型的数据
        //使用泛型之后,集合中的数据类型统一了

        List<Animal>mylist=new ArrayList<Animal>();

        Cat cat=new Cat();
        Bird bird=new Bird();

        mylist.add(cat);
        mylist.add(bird);

        //获取迭代器
        //这表示迭代类型是Animal
        Iterator<Animal> iterator=mylist.iterator();

        while (iterator.hasNext()){
            //使用泛型之后,每一次迭代返回的数据都是Animal类型
            Animal a=iterator.next();

            /*
            *Object obj=iterator.next();
             *if(obj InstanceOf Animal)
             * Animal a=(Animal)obj;
             * */
            //这里不需要强制类型转换,直接调用
            a.move();
            //调用子类的方法还需要转型
            if(a instanceof Bird){
                
                ((Bird) a).fly();
            }

        }
    }
}
class Animal{
    public void move(){
        System.out.println("动物在动!");
    }
}
class Cat extends Animal{
    public void catchMouse(){
        System.out.println("猫抓老鼠!");

    }
}
class Bird extends Animal{
    public void fly(){
        System.out.println("鸟在飞!");
    }
}

泛型可以自定义

package Collection.Generic;
/*
泛型是可以自定义的
泛型的标识符通常用E、T
element和type
 */

//在类中使用泛型
public class Test02<E> {
    //方法中泛型与类中保持一致
    public void doSomething(E e){
        System.out.println(e);
    }

    public static void main(String[] args) {
        Test02<String> test02=new Test02<>();
        //调用doSomething方法中只能是字符串类型
        test02.doSomething("abc");

        //不用泛型,就是Object类型
        Test02 test=new Test02();
        test.doSomething(new Object());

    }

}

演示一下HashSet和TreeSet集合特点

package Collection.HashSet;

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

/*
演示一下HashSet的特点,无序不可重复
 */
public class Test01 {
    public static void main(String[] args) {
        Set<String> strings=new HashSet<>();
        //添加元素
        strings.add("hello1");
        strings.add("hello1");
        strings.add("hello1");
        strings.add("hello5");
        strings.add("hello4");
        strings.add("hello3");

        //遍历
        for (String s:strings) {
            System.out.println(s);
        }
        /*
        输出:
        hello1
        hello4
        hello5
        hello3
        1.存储时顺序和取出来顺序不一样
        2.不可重复
        3.实际上是存储到HashMap的key部分
         */
    }
}

package Collection.HashSet;

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

/*
TreeSet集合存储元素的特点:
    1.无序不可重复,但是存储元素自动按照大小顺序排序!
    称为:可排序集合
    2.无序指的是没有下标,存入和取出的顺序不同
 */
public class Test02 {
    public static void main(String[] args) {
        Set<String> strings=new TreeSet<>();

        strings.add("A");
        strings.add("A");
        strings.add("C");
        strings.add("D");
        strings.add("B");
        strings.add("B");

        for (String s:strings) {
            System.out.println(s);

        }
        /*
        A
        B
        C
        D
         */
    }
}


Map接口常用方法

package Map;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/*
Map接口中常用的方法
1.Map和Collection没有继承关系
2.Map集合以key和value的方式存储数据
    key和value都是引用数据类型。
    都是存储对象的内存地址
    key起主导作用,value是key的附属
3.Map接口中常用方法:
    V put(K key,V value)
    void clear()
    boolean containsKey(Object key)
    boolean containsValue(Object value)
    boolean isEmpty
    V get(Object key)通过key获取value
    boolean isEmpty()
    Set<K> keySet() 获取Map集合中所有的key
    V put(K key,V value)
    V remove(Object key) 通过key删除键值对
    int size()
    Collection<V> values() 获取Map集合中所有的value,返回一个Collection
    Set<Map.Entry<K,V>> entrySet()将Map集合转换成Set集合,Map.Entry是一个静态内部类
 */
public class Test01 {
    public static void main(String[] args) {
        //创建Map集合对象
        Map<Integer,String>map=new HashMap<>();
        //向Map中添加键值对
        map.put(1,"zhangsan1");
        map.put(2,"zhangsan2");
        map.put(3,"zhangsan3");
        map.put(4,"zhangsan4");
        //通过key获取value
        String value=map.get(2);
        System.out.println(value);
        //zhangsan2

        //获取键值对数量
        System.out.println(map.size());//4
        map.remove(2);
        System.out.println(map.size());//3

        //判断是否包含某个key,value
        System.out.println(map.containsKey(2));//false
        System.out.println(map.containsValue("zhangsan1"));//true
        //contains方法底层调用的都是equals方法,自定义类型需要重写equals方法
        System.out.println(map.containsValue(new String("zhangsan1")));//true

        //获取所有的value
        Collection<String>values=map.values();
        for (String s:values) {
            System.out.println(s);
            /*
            zhangsan1
            zhangsan3
            zhangsan4
             */
        }

        //清空集合
        map.clear();
        System.out.println(map.size());//0

    }
}

package Map;

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

/*
Map集合的遍历
 */
public class Test02 {
    public static void main(String[] args) {
        //第一种方式,通过遍历key来遍历value
        Map<Integer,String>map=new HashMap<>();
        //向Map中添加键值对
        map.put(1,"zhangsan1");
        map.put(2,"zhangsan2");
        map.put(3,"zhangsan3");
        map.put(4,"zhangsan4");
        //遍历map集合,获取所有的key,所有的key是一个Set集合
        Set<Integer> keys=map.keySet();
        //遍历所有的key,获取value
        //迭代器
        Iterator<Integer>iterator=keys.iterator();
        while (iterator.hasNext()){
            Integer key=iterator.next();
            //通过key来获取value
            String value=map.get(key);
            System.out.println(key+"="+value);
            /*
            1=zhangsan1
            2=zhangsan2
            3=zhangsan3
            4=zhangsan4
             */
        }
        //增强for循环
        for(Integer key:keys){
            System.out.println(key+"="+map.get(key));
            /*
            1=zhangsan1
            2=zhangsan2
            3=zhangsan3
            4=zhangsan4
             */
        }

        //第二种方法:Set<Map.Entry<K,V>> entrySet()
        /*
        这个方法是吧map集合直接全部转换成Set集合。
        Set集合中元素的类型是:Map.Entry<K,V>
         */
        Set<Map.Entry<Integer,String>> set=map.entrySet();
        //遍历Set集合,每一次取出一个Node
        //迭代器
        Iterator<Map.Entry<Integer,String>> iterator2=set.iterator();
        while (iterator2.hasNext()){
            Map.Entry<Integer,String> node =iterator2.next();
            Integer key=node.getKey();
            String value=node.getValue();
        }

        //增强for
        for(Map.Entry<Integer,String> node:set){
            Integer key=node.getKey();
            String value=node.getValue();
            System.out.println(key+"="+value);
            /*
            1=zhangsan1
            2=zhangsan2
            3=zhangsan3
            4=zhangsan4
             */
        }

    }
}

HashMap

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

package collection.HashMap;

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

/*
HashMap集合
    1.HashMap的底层是哈希表的数据结构
    2.哈希表:
        是一个数组和单向链表的结合体
        数组:查询效率高,随机增删效率低
        单向链表:随机增删效率高,查询效率低
        哈希表将以上两种数据结构融合在一起
    3.哈希表:一维数组,数组中每一个元素是一个单向链表
    4.最主要掌握的是:存取的两个方法
        map.put(k,v)
        v=map.get(k)
        增删都在链表上完成,查询也只是部分扫描
    5.HashMap集合的key部分特点:
        无序、不可重复
        为什么会无序?因为不一定会挂在哪个单向链表上
        equals方法来保证HashMap集合的key不可重复
        如果key重复了,value会覆盖

        放在HasMap集合中key部分的元素,其实就是放到了HashSet集合中。
        所以HashSet集合中的元素也需要重写hashCode()+equals()方法
    6.哈希表HashMap使用不当时,无法发挥性能
        hashCode()返回值是数组的下标,如果hashCode()返回值固定,哈希表相当于一个链表
        如果每一个hashCode()返回值都不同,相当于一个数组
     7.重点:放在HashMap集合key部分的元素,以及放在HashSet集合中的元素,需要同时重写hashCode和equals方法。
     8.HashMap的默认容量是16(2的4次),默认加载因子是0.75(了解),当容量达到75%时,数组开始扩容

 */
public class Test01 {
    public static void main(String[] args) {
        //测试HashMap集合key部分的元素特点
        //Integer是key,它的hashCode和equals都重写了
        Map<Integer,String> map=new HashMap<>();
        map.put(1,"zhangsan1");
        map.put(2,"zhangsan2");
        map.put(3,"zhangsan3");
        map.put(1,"lisi");//key重复的时候value会自动覆盖
        map.put(5,"wangwu");

        System.out.println(map.size());//4

        //遍历
        Set<Map.Entry<Integer,String>> set=map.entrySet();
        for (Map.Entry<Integer,String> entry:set){
            System.out.println(entry.getKey()+"="+entry.getValue());
            //验证结果就是:HashMap集合key部分元素,无序不可重复
        }

    }


}

package collection.HashMap;

import java.util.HashSet;
import java.util.Set;
/*
1.向Map集合中存取,首先调用的是hashCode方法,然后是equals方法
put(k,v)时,当数组下标对应位置是null,不需要调用equals方法
get(k)时,如果单向链表上只有一个元素,也不用调用equals方法
2.注意:
如果一个类的equals()方法重写了,那么hashCode()方法也必须重写
并且equals方法返回如果是true,hashCode返回值必须一样
 */
//终极结论,放在HashMap集合key部分、以及HashSet中的元素,要同时重写hashCode和equals

public class Test02 {
    public static void main(String[] args) {
        Student student1=new Student("zhangsan");
        Student student2=new Student("zhangsan");

        //重写equals方法之前
        //System.out.println(student1.equals(student2));//false

        //重写equals方法之后
        System.out.println(student1.equals(student2));//true

        System.out.println(student1.hashCode());//885284298 重写:-1432604525
        System.out.println(student2.hashCode());//1389133897  重写:-1432604525

        // s1.equals(s2)结果已经是true,表示s1和s2是一样的,
        //那么往HashSet集合中放,按理说只能放一个
        Set<Student> students=new HashSet<>();
        students.add(student1);
        students.add(student2);
        System.out.println(students.size());//不重写hashCode,结果是2,不符合HashSet存储特点
        //所以equals重写了,hashCode()必须重写
        //重写之后结果是1
    }

}
/*====================================================================*/

package collection.HashMap;

import java.util.Objects;

public class Student {
    private String name;
    public Student(){

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    //equals重写,如果名字一样,表示同一个学生


    @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);
    }

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

properties 类

package collection.HashMap.properties;

import java.util.Properties;

/*
掌握properties属性类的相关方法
Properties是一个Map集合,继承Hashtable,Properties的key与value都是String类
Properties称为属性类对象,线程安全
 */
public class Test01 {
    public static void main(String[] args) {
        //掌握两个方法,一个存一个取
        Properties properties=new Properties();
        properties.setProperty("User","name");
        properties.setProperty("password","123");

        //通过key来获取value
        String USer=properties.getProperty("User");
        String password=properties.getProperty("password");

        System.out.println(USer+password);
    }

}

TreeSet&TreeMap

package collection.TreeSet;

import java.util.TreeSet;

/*
1.TreeSet集合底层实际上是一个TreeMap
2.TreeMap集合底层是一个二叉树
3.放到TreeSet集合中的元素:无序不可重复,但是可以按照元素大小顺序自动排序
称为可排序集合。
 */
public class Test01 {
    public static void main(String[] args) {
        //创建一个TreeSet集合
        TreeSet<String >ts=new TreeSet<>();

        //添加String
        ts.add("zhangsan4");
        ts.add("zhangsan1");
        ts.add("zhangsan2");
        ts.add("zhangsan3");

        for (String s:ts){
            System.out.println(s);
            /*
            zhangsan1
            zhangsan2
            zhangsan3
            zhangsan4
            自动排序了
             */
        }
    }
}

package collection.TreeSet;

import java.util.TreeSet;

/*
自定义排序类型
 */
public class Test02 {
    public static void main(String[] args) {
        Person person1=new Person(25);
        Person person2=new Person(35);
        Person person3=new Person(37);
        Person person4=new Person(45);

        //创建TreeSet集合
        TreeSet<Person> persons=new TreeSet<>();
        //添加元素
        persons.add(person1);
        persons.add(person2);
        persons.add(person3);
        persons.add(person4);
        //这里要注意实现Compareble接口,对象才可以排序,否则会报错
        //如果没有排序,二叉树就无法存元素
        //遍历
        for(Person p:persons){
            System.out.println(p);
            /*
            Person{age=25}
            Person{age=35}
            Person{age=37}
            Person{age=45}
             */
        }
    }
}
//实现接口并且重写比较的方法
class Person implements Comparable<Person>{
    private int age;
    public Person(){

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

    public int getAge() {
        return age;
    }

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

    //需要在这个方法中编写比较的逻辑,或者说比较规则
    //按照年龄排序
    /*
    k.compareTo(t.key)
    用参数key和集合中每一个k进行比较,返回值:-1,0,1
     */

    @Override
        public int compareTo(Person p){
        return this.age-p.age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                '}';
    }
}

package collection.TreeSet;

import collection.HashMap.Student;

import java.util.TreeSet;

/*
先按照年龄升序,如果年龄一样,在按照姓名升序
 */
public class Test03 {
    public static void main(String[] args) {
        TreeSet<Student0> students=new TreeSet<>();
        //添加元素
        students.add(new Student0("zhangsan1",15));
        students.add(new Student0("zhangsan3",19));
        students.add(new Student0("zhangsan2",19));
        students.add(new Student0("zhangsan4",25));

        for (Student0 s:students){
            System.out.println(s);
            /*
            Student{name='zhangsan1', age=15}
            Student{name='zhangsan2', age=19}
            Student{name='zhangsan3', age=19}
            Student{name='zhangsan4', age=25}
             */
        }
    }
}
 
class Student0 implements Comparable<Student0>{
    String name;
    int age;

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

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

    /*
    返回值很重要,返回0,表示元素相同,返回大于0,在右子树上找
    返回小于零,会继续在左子树上找。
     */
    @Override
    public int compareTo(Student0 o) {
        if(this.age==o.age){
            //排序规则
            //当年龄相同,按照姓名比较,String类型可以直接调用compareTo()方法
            return this.name.compareTo(o.name);

        }else{
            return this.age-o.age;
        }
    }
}

package collection.TreeSet;

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

/*
TreeSet集合中元素可排序的第二种方式:使用比较器
 */
public class Test04 {
    public static void main(String[] args) {
        // TreeSet<Tortoise>tortoises=new TreeSet<>();
        // 这样不行,没有通过构造方法传递一个比较器进去
        //需要给构造方法传递一个比较器进去

        //TreeSet<Tortoise> tortoises=new TreeSet<>(new TotoiseComparator());
        //使用匿名内部类
        TreeSet<Tortoise>tortoises=new TreeSet<>(new Comparator<Tortoise>() {
            @Override
            public int compare(Tortoise o1, Tortoise o2) {
                return o1.age-o2.age;
            }
        });
        //添加元素
        tortoises.add(new Tortoise(1000));
        tortoises.add(new Tortoise(800));
        tortoises.add(new Tortoise(100));
        tortoises.add(new Tortoise(400));

        //遍历
        for (Tortoise s:tortoises){
            System.out.println(s);
        }
    }

}
class Tortoise{
    int age;
    public Tortoise(int age){
        this.age=age;
    }

    @Override
    public String toString() {
        return "Tortoise{" +
                "age=" + age +
                '}';
    }
    //单独在这里编写一个比较器
    //比较器实现Comparator排序接口

}
//class TotoiseComparator implements Comparator<Tortoise>{
//    @Override
//    public int compare(Tortoise o1, Tortoise o2) {
//        return o1.age-o2.age;
//    }
//    也可以使用匿名内部类
}

TreeSet集合中实现排序的两种方法:

Comparable是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。而Comparator是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。

Comparable相当于“内部比较器”,而Comparator相当于“外部比较器”。

两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了.

​ 如果比较规则只有一个,使用Comparable排序接口;如果比较规则有多个,使用Comparator比较器。

自平衡二叉树数据结构

  1. TreeSet和TreeMap是自平衡二叉树,遵循左小右大原则存放。

  2. 遍历二叉树的三种方式:按照根的位置

    前序遍历:根左右

    中序遍历:左根右

    后续遍历:左右根

  3. TreeSet集合和TreeMap集合,Iterator迭代器采用中序遍历方式

Collections 集合工具类

package collection.Collections;

import collection.HashMap.Student;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/*
Collection 集合接口
Collections 集合工具类,方便集合的操作
 */
public class Test01 {
    public static void main(String[] args) {

        //ArrayList集合不是线程安全的
        List<Student> list=new ArrayList<>();
        //变成线程安全的
        Collections.synchronizedList(list);
        
        list.add(new Student("zhangsan1"));
        list.add(new Student("zhangsan2"));
        list.add(new Student("zhangsan4"));
        list.add(new Student("zhangsan3"));
        //排序
        //注意,对list集合中的元素排序,需要保证list集合中的元素实现了Comparable接口
        Collections.sort(list);
        for(Student s:list){
            System.out.println(s);
        }
        //对Set集合怎么排序呢?
        Set<String> set=new HashSet<>();
        set.add("Baby");
        set.add("Honey");
        set.add("girl");
        //将set集合转换为List集合
        List<String>list1=new ArrayList<>(set);//set作为参数传进去
        Collections.sort(list1);
        for (String s:list1){
            System.out.println(s);
        }
    }
    static class Student implements Comparable<Student>{
        public 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 int compareTo(Student o) {
            return this.name.compareTo(o.getName());
        }

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


回顾List集合:

  1. 每个集合的创建。
  2. 向集合中添加元素
  3. 从集合中取出元素
  4. 遍历集合
  5. 主要的集合类:ArrayList、LinkedList、HashSet、TreeSe、HashMap、Properties、TreeMap
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值