java第十四章:集合

java第十四章:集合

集合框架体系图

单列集合继承图

单列集合继承图

双列集合继承图

双列集合继承图

集合框架体系解读

1.集合主要是两组:
	1):单列集合
	2):双列集合
2.Collectin 接口有两个重要的子接口 List Set ,他们的实现子类都是单列集合
3.Map 接口的实现子类 是双列集合,存放的 K-V
ArrayList arrayList = new ArrayList();
arrayList.add("jack");

HashMap hashMap = new HashMap();
hashMap.put("NO1","北京");

Collection接口基本介绍

1.Collection实现子类可以存放多个元素,每个元素可以是Object
2.有些Collection的实现类,可以存放重复的元素,有些不可以
3.有些Collection的实现类,有些是有序的(List),有些是无序的(Set)
4.Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的

Collection接口常用方法

CRUD
  • add
  • remove
  • contains
  • size
  • clear
  • isEmpty
  • addAll
  • removeAll
  • containsAll
package com.lcz.collection;

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

/**
 * @author lcz
 * @version 1.0
 * 关于:
 *      CRUD
 *      - add
 *      - remove
 *      - contains
 *      - size
 *      - clear
 *      - isEmpty
 *      - addAll
 *      - removeAll
 *      - containsAll
 */
@SuppressWarnings({"all"})
public class Collection_ {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(1);
        list.add("sadfsa");
        list.add(new Integer(10));
        System.out.println(list.contains(1));
        list.remove(1);
        System.out.println(list.size());
        System.out.println(list);
        list.clear();
        System.out.println(list);
        System.out.println(list.isEmpty());
        List list1 = new ArrayList();
        list1.add('s');
        list1.add("sdafs");
        list.add(new Integer(100));
        list.addAll(0,list1);
        System.out.println(list);
        list.containsAll(list1);
        list.removeAll(list1);
        System.out.println(list);


    }
}

遍历集合的三种方式
Iterator(迭代器)

基本介绍

1.Iterator对象称为迭代器,主要用于遍历 Collection 集合中的元素
2.所有实现了Collection接口的集合类都有一个iterator()方法,用于返回一个实现了Iterator接口的对象,即可以返回一个迭代器
3.Iterator 仅用于遍历集合,本身并不存放对象

执行原理

迭代器执行原理

增强for:简化版迭代器
普通for
//遍历集合三种方式
        //(1):迭代器
        //快捷键ii
        System.out.println("===迭代器===");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println(obj);
        }
        //(2):增强for:底层仍调用迭代器,所以为简化版迭代器
        //快捷键I
        System.out.println("===增强for===");
        for(Object obj:list){
            System.out.println(obj);
        }
        //(3):普通for
        //快捷键fori
        System.out.println("===普通for===");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

List接口基本介绍

List接口是Collection接口的子接口
1.List集合类中元素有序(即添加顺序 和 取出顺序一致)、且可重复
2.List集合类支持索引
3.List接口的实现类:LinkedListArrayListVector

List接口常用方法

CRUD

  • add(int index,Object ele)
  • addAll(int index,Collection eles)
  • get(int index)
  • indexOf(Object obj)
  • lastIndexOf(Object obj)
  • remove(int index)
  • set(int index,Object ele)
  • subList(int fromIndex,int toIndex):返回从fromIndex到toIndex位置的 子集合
list.set(0,90);
System.out.println(list);
System.out.println(list.get(0));
System.out.println(list.indexOf(90));
list.add("sadfsadf");
list.add('c');
list.add(1,50);
System.out.println(list);
System.out.println(list.subList(0,2));

List三种遍历方式

  • 迭代器

  • 增强for

  • 普通for

List排序

List排序

package com.lcz.collection;

import com.sun.javafx.fxml.expression.UnaryExpression;

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

/**
 * @author lcz
 * @version 1.0
 * 关于:
 *      List接口的实现类进行排序并输出
 */
public class List_01 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(new Book("西游记",10));
        list.add(new Book("西游",9));
        list.add(new Book("西游记降魔",12));
        list.add(new Book("西游记3",11));
        System.out.println("===未排序===");
        for (Object o :list) {
            System.out.println(o);
        }
        bubbleSort(list);
        System.out.println("===按价格从低到高排序===");
        for (Object o :list) {
            System.out.println(o);
        }

    }
    public static void bubbleSort(List list){
        for (int i = 0; i < list.size(); i++) {
            for (int j = 0; j < list.size() - 1 - i; j++) {
                Book book1 = (Book) list.get(j);
                Book book2 = (Book) list.get(j+1);
                if(book1.getPrice() > book2.getPrice()){
                    list.set(j,book2);
                    list.set(j+1,book1);
                }
            }
        }
    }
}
class Book{
    private String name;
    private double price;

    public Book(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

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

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "名称:" + name + "\t" + "价格:" + price;
    }
}

ArrayList类

ArrayList注意事项

1.ArrayList允许加入所有元素,包括null,且可多个null
2.ArrayList是由数组来实现数据存储的
3.ArrayList基本等同于Vector,但ArrayList存在线程安全问题(执行效率高),
  多线程情况,不建议使用ArrayList

ArrayList底层结构和源码分析

结论
![ArraysList源码1](D:%5C%E6%A1%8C%E9%9D%A2%5Cjava%E7%AC%AC%E5%8D%81%E5%9B%9B%E7%AB%A0%E9%9B%86%E5%90%88%5CArraysList%E6%BA%90%E7%A0%811.png1.ArrayList中维护了一个Object类型的数组elementData.
  transient Object[] elementData;//transient 表示瞬间,短暂的,表示该属性不会被序列化
2.当创建ArrayList对象时,如果为无参构造器,则初始elementData容量为0,第一次添加,扩容至10,以后扩容,扩容至1.5倍
3.如果指定大小的构造器,初始elementData容量为指定大小,需扩容,则扩容1.5倍
分析
无参构造器创建对象

ArrayList无参构造器扩容机制1

ArrayList无参构造器扩容机制2

ArrayList无参构造器扩容机制3

ArrayList无参构造器扩容机制4

debug详细信息显示设置

debug详细信息显示设置

有参构造器创建对象

ArrayList有参构造器扩容机制1

ArrayList有参构造器扩容机制2

Vector类

基本介绍

1.底层也是一个对象数组
2.Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized

Vector和ArrayList的比较

Vector和ArrayList比较

源码分析

Vector底层源码1

Vector底层源码2

LinkedList类

基本介绍

1.底层实现了双向链表和双端队列特点
2.可以添加任意元素(元素可以重复),包括null
3.线程不安全,没有实同步

底层操作机制

1.底层维护了一个双向链表
2.LinkedList中维护了两个属性first、last分别指向首结点和尾结点
3.每个结点(Node对象),里面又维护了prev、next、item三个属性
4,所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高

模拟一个双向链表

package com.lcz.collection.list;

/**
 * @author lcz
 * @version 1.0
 *
 *需求:
 *      模拟一个双向链表
 */
public class LinkedList_ {
    public static void main(String[] args) {
        Node node = new Node(1);
        Node node1 = new Node(2);
        Node node2 = new Node(3);
        node.next = node1;
        node1.next = node2;
        node1.prev = node;
        node2.prev = node1;
        Node first = node;
        Node last = node2;
        //从头到尾进行遍历
        System.out.println("从头到尾进行遍历");
        while (first != null){
            System.out.println(first.item);
            first = first.next;
        }
        //从尾到头进行遍历
        System.out.println("从尾到头进行遍历");
        while (last != null){
            System.out.println(last.item);
            last = last.prev;
        }
        //插入一个新节点到node1和node2之间
        System.out.println("插入一个node3:dsaf到node1:2和node2:3之间");
        Node node3 = new Node("dsaf");
        node3.prev = node1;
        node3.next = node2;
        node1.next = node3;
        node2.prev = node3;
        first = node;
        last = node2;
        while (first != null){
            System.out.println(first.item);
            first = first.next;
        }
    }
}
class Node{
    public Node prev;
    public Node next;
    public Object item;

    public Node(Object item) {
        this.item = item;
    }

    public Object getItem() {
        return item;
    }

    public void setItem(Object item) {
        this.item = item;
    }

    @Override
    public String toString() {
        return "Node{" +
                "item=" + item +
                '}';
    }
}

遍历三种方式

  • 迭代器

  • 增强for

  • 普通for

Set接口

基本介绍

1.无序(添加和取出的顺序不一致),没有索引
2.不允许重复元素,所以最多包含一个null

常用方法

是Collection的子接口,常用方法和Collection一样

遍历方式两种

  • 迭代器
  • 增强for

注:因为不能索引方式获取元素,所以不能用普通for遍历

HashSet类

基本介绍

1.实现Set接口
2.HashSet实际上是HashMap:无参构造器创建一个HashMap对象
3.可以存放null值,但只能有一个
4.不保证元素有序,hash后,它的取出顺序一旦定下来就不变了
5.不能有重复元素/对象

HashSet底层机制说明

HashSet底层是HashMap,HashMap底层是(数组+链表+红黑树)

模拟简单的数组+链表结构
package com.lcz.collection.set;

/**
 * @author lcz
 * @version 1.0
 *
 * 需求:
 *      模拟HashSet的底层
 *      HashMap的底层
 *      数组+链表结构
 *
 */
public class Structure {
    public static void main(String[] args) {
        //模拟一个HashSet的底层(HashMap的底层结构)
        //1.创建一个数组,数组类型为 Node
        //2.有些人直接把 Node[]当成 表
        Node[] table = new Node[16];
        Node node1 = new Node("lcz");
        table[0] = node1;
        Node node2 = new Node("lhc");
        node1.next = node2;


    }
}
class Node{
    public Object obj;
    public Node next;

    public Node(Object obj) {
        this.obj = obj;
    }
}

结论
1.添加一个元素时,先获取元素的hash值(hashcode()方法通过一个计算得到),将hash值转成--索引值
2.找到存储数据表table,看这个索引的位置是否已经存放元素
3.若没有,直接加入
4.若有,则判断是否:
	(1):两个Node结点的hash值一样
		并且满足一下两个条件之一:
				a:两个Node结点的key值(也就是添加的对象)相等(即地址相等)
				b:添加的结点的key值不为空,且调用equals方法与另一个结点的key值相同,此equals方法可以重写,由程序员来控制
	若满足上述所说:则不添加
	若不满足,则添加至最后
5.Java8中,如果一个链表的元素个数到达TREEIFY_THRESHOLD(默认是8),并且table的大小 >= MIN_TREEIFY_CAPACITY(默认 64),就会进行树化(红黑树)
过程分析
package com.lcz.collection.set;

import java.util.HashSet;

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      Debug调试
 *      对hashSet源码进行解读:
 *      1.执行 HashSet()
 *      public HashSet() {
 *         map = new HashMap<>();
 *     }
 *     2.执行 add()
 *     public boolean add(E e) {//e = "java"
 *         return map.put(e, PRESENT)==null;// HashSet类的(private static final) PRESENT = new Object();
 *     }
 *     3. 执行put(),该方法会执行 hash(key) 得到key对应的hash值,算法:(h = key.hashCode()) ^ (h >>> 16)
 *      public V put(K key, V value) {//key = "java" value = PRESENT 共享
 *         return putVal(hash(key), key, value, false, true);
 *     }
 *     4.执行 putVal()
 *     final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
 *                    boolean evict) {
 *         Node<K,V>[] tab; Node<K,V> p; int n, i;//定义了辅助变量
 *         //table 就是 HashMap 的一个数组,类型是 Node[]
 *         //if 语句表示如果当前table是 null,或者长度为0
 *         //就进行第一次扩容,到16个空间
 *         if ((tab = table) == null || (n = tab.length) == 0)
 *             //resize()进行数组的扩容
 *             n = (tab = resize()).length;
 *         //(1):根据key,得到hash,与计算该key应该存放到table表中哪个索引位置
 *         //并把这个位置的对象赋给p
 *         //(2):判断p是否为null
 *         //(2.1):若 p 为null,表示还没有存放元素,就创建一个Node
 *         //(2.2):并存放此索引位置
 *         if ((p = tab[i = (n - 1) & hash]) == null)
 *             tab[i] = newNode(hash, key, value, null);
 *         else {
 *             //一个开发技巧:在需要局部变量(辅助变量)时,再创建
 *             Node<K,V> e; K k;
 *             //如果当前索引位置对应的第一个元素和准备添加的key的hash值一样
 *             //并且满足 下面两个条件之一:
 *             //(1):准备加入的 key 和 p 指向的Node结点的 key 是同一个对象(即地址相等)
 *             //(2):准备加入的 key 的 equals()方法 和 p 指向的Node结点的 key 比较后相同
 *                   equals方法可以重写,由程序员来控制
 *             //就不能加入
 *             if (p.hash == hash &&
 *                 ((k = p.key) == key || (key != null && key.equals(k))))
 *                 e = p;//直接走向下方的添加失败的if结构
 *             //再判断 p 是不是一颗 红黑树
 *             //如果是 红黑树,就以红黑树的方式putTreeVal()进行添加
 *             else if (p instanceof TreeNode)
 *                 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
 *             else {//table对应索引位置可能已经是一个链表,需使用for循环比较
 *                   //(1) 依次和该链表的元素进行比较,都不相同,则加入到该链表的最后
 *                   //    注意把元素添加到链表后,立即判断,该链表是否已经达到8个结点
 *                   //    若达到,则调用treeifyBin,对当前这个链表进行树化(转成红黑树)
 *                   //    注意:转成红黑树时要进行判断,判断条件
 *                   //    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
 *                   //    若条件成立,则先table扩容
 *                   //    不成立,才进行转成红黑树
 *                   //(2) 依次和该链表的每一个元素进行比较的过程中,若有相同情况,就直接break;
 *                   //     此时,循环一半,此时 e != null , 直接走向添加失败的if语句
 *                 for (int binCount = 0; ; ++binCount) {
 *                      //只有循环到最后e为null,才会添加成功,循环一般都会走下面的if语句添加失败
 *                     if ((e = p.next) == null) {
 *                         p.next = newNode(hash, key, value, null);
 *                         if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
 *                             treeifyBin(tab, hash);
 *                         break;
 *                     }
 *                     if (e.hash == hash &&
 *                         ((k = e.key) == key || (key != null && key.equals(k))))
 *                         break;
 *                     p = e;
 *                 }
 *             }
 *             //添加失败的if语句
 *             if (e != null) { // existing mapping for key
 *                 V oldValue = e.value;
 *                 if (!onlyIfAbsent || oldValue == null)
 *                     e.value = value;
 *                 afterNodeAccess(e);
 *                 return oldValue;//
 *             }
 *         }
 *         //走到这里就添加成功
 *         ++modCount;
 *         if (++size > threshold)//size 指添加的结点个数
 *             resize();//
 *         afterNodeInsertion(evict);
 *         return null;
 *     }
 */
public class Set_ {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        System.out.println(hashSet.add("java"));
        System.out.println(hashSet.add("lcz"));
        System.out.println(hashSet.add("java"));
        System.out.println("set = " + hashSet);
    }
}

验证扩容机制
package com.lcz.collection.set;

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

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      验证扩容机制: Debug调试
 *          1.HashSet的底层是HashMap,第一次添加时,table 数组扩容到16
 *          2.临界值是(threshold) 是 16 * 加载因子(loadFactor)是0.75 = 12
 *          3.如果table数组中的元素个数 达到 临界值12,就会扩容到 16 *2 = 32
 *          4.新的临界值,依次类推
 */
public class Set_01 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        for (int i = 0; i < 100; i++) {
            hashSet.add(i);
        }
    }

}

验证树化机制
package com.lcz.collection.set;

import java.util.HashSet;

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      验证树化机制:Debug调试
 */
public class Set_02 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        for (int i = 0; i < 12; i++) {
            hashSet.add(new A(i));
        }
    }
}
class A{
    private int n;

    public A(int n) {
        this.n = n;
    }

    @Override
    public int hashCode() {
        return 100;
    }
}

验证扩容机制条件
package com.lcz.collection.set;

import java.util.HashSet;

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      验证HashSet扩容机制条件:
 *                  是元素个数大于临界值,不是数组的12个空间被占用
 */
public class Set_03 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        for (int i = 0; i < 8; i++) {
            hashSet.add(new A1(i));
        }
        for (int i = 0; i < 8; i++) {
            hashSet.add(new B(i));
        }
    }
}
class A1{
    private int n;

    public A1(int n) {
        this.n = n;
    }

    @Override
    public int hashCode() {
        return 100;
    }
}
class B{
    private int n;

    public B(int n) {
        this.n = n;
    }

    @Override
    public int hashCode() {
        return 200;
    }
}

HashSet最佳实践

HashSet最佳实践

package com.lcz.collection.set.hashset;

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

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      1.定义一个Employee类,包含name、age属性
 *      2.创建3个Employee对象放入HashSet中
 *      3.要求当name和age相同时,认为是相同员工,不能添加到HashSet集合中
 */
public class Exercise01 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add(new Employee("lcz",20));
        hashSet.add(new Employee("lhc",20));
        hashSet.add(new Employee("孙悟空",1000));
        hashSet.add(new Employee("孙悟空",1000));
        System.out.println(hashSet);
    }

}
class Employee{
    private String name;
    private int age;

    public Employee(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;
    }

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

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

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

HashSet课后练习

HashSet课后练习

package com.lcz.collection.set.hashset;

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

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      1.还是Employee1类,包含name、sal、birthday(MyDate类型,包含:year、month、day)
 *      2.要求同exercise01
 * 注意:因为Employee1重写的equals调用Objects的equals:
 *                      public static boolean equals(Object a, Object b) {
                     *         return (a == b) || (a != null && a.equals(b));
                     *     }
 *      所以需要重写MyDate类的equals方法
 *      因为Employee1重写的hashCode()方法返回的hash值是根据所有参数的hashCode值经过一个算法得出的
 *                   public static int hashCode(Object a[]) {
                 *         if (a == null)
                 *             return 0;
                 *
                 *         int result = 1;
                 *
                 *         for (Object element : a)
                 *             result = 31 * result + (element == null ? 0 : element.hashCode());
                 *
                 *         return result;
                 *     }
 *      所以要重写MyDate类的hashCode方法
 */
public class Exercise02 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add(new Employee1("lhc",30000,new MyDate(2004,11,27)));
        hashSet.add(new Employee1("lcz",30000,new MyDate(2004,11,27)));
        hashSet.add(new Employee1("孙悟空",50,new MyDate(1655,11,10)));
        hashSet.add(new Employee1("lhc",30000,new MyDate(2004,11,27)));
        for (Object o :hashSet) {
            System.out.println(o);
        }

    }
}
class Employee1{
    private String name;
    private double sal;
    private MyDate birthday;

    public Employee1(String name, double sal, MyDate birthday) {
        this.name = name;
        this.sal = sal;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public MyDate getBirthday() {
        return birthday;
    }

    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Employee1{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", birthday=" + birthday +
                '}';
    }

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

    @Override
    public int hashCode() {
        return Objects.hash(name, birthday);
    }
}
class MyDate{
    private int year;
    private int month;
    private int day;

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyDate myDate = (MyDate) o;
        return year == myDate.year && month == myDate.month && day == myDate.day;
    }

    @Override
    public int hashCode() {
        return Objects.hash(year, month, day);
    }
}

LinkedHashSet类

基本介绍

1.LinkedHashSet是HashSet的子类
2.LinkedHashSet 底层是一个 LinkedHashMap,其是HashMap的子类,底层维护了一个数组+双向链表
3.LinkedHashSet用链表维护元素的次序,使得元素插入顺序和取出顺序一致,即有序
4,仍不可添重复元素

继承图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

底层机制

LinkedHashSet底层机制

1.LinkedHashSet中维护了一个hash表和双向链表
	(LinkedHashSet有head 和 tail)
2.每个结点有 pre 和 next 属性,形成双链表
3.在添加一个元素时,先求hash值,再求索引,确定该元素再hashtable的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加)
	tail.next = newElement;/简单指定
	newElement.pre = tail;
	tail = newElement;
4.确保了插入顺序和遍历顺序一致
源码解读
package com.lcz.collection.set.linkedhashset;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * @author lcz
 * @version 1.0
 * 需求:Debug调试
 *      LinkedHashSet类源码解读
 *
 */
public class LinkedHashSet_ {
    public static void main(String[] args) {
        LinkedHashSet set = new LinkedHashSet();
        set.add("java");
        set.add(456);
        set.add(456);
        set.add("lhc");
        set.add("lcz");
        System.out.println("set = " + set);
    }
}
//1.LinkedHashSet 底层维护的是一个LinkedHashMap(是HashMap的子类)
//2.LinkedHashSet 底层结构(数组+双向链表)
//3.添加第一次时,直接将 table数组 扩容至16,存放的结点类型是LinkedLinkedHashMap$Entry
//4.数组是 HashMap$Node[] 存放的元素/数据是 LinkedHashMap$Entry类型
    //展现的是多态,所以Entry继承Node,二者都是静态内部类
    //之所以继承:因为双向链表实现需要扩展出before和after属性
/*
        继承关系是在内部类完成的
        static class Entry<K,V> extends HashMap.Node<K,V> {
                Entry<K,V> before, after;
                Entry(int hash, K key, V value, Node<K,V> next) {
                    super(hash, key, value, next);
                }
            }
 */

课后练习同HashSet类

Map接口

特点:

1.Map与Collection并列存在,用于保存具有映射关系的数据:Key:Value
2.Map中的 key 和 value 可以是任何引用类型的数据,会封装到HashMao$Node
3.Map中的 key 不允许重复,但 value 可以重复
4.Map中的 key 可以为null,value 也可以为null,注意 key 为null,只能有一个,value 为null,可以多个
5.常用String类作为Map的 key
6.key 和 value 之间存在单向一对一关系,即通过指定的key总能找到对应的value
7.Map存放数据的key-value示意图,一对 k-v 是放在一个HashMap$Node中的,又因为Node实现了 Entry 接口,所以一个Node结点就是一个Entry接口对象,将这些接口对象放到一个 类型为Entry的EntrySet(HashMap$EntrySet)中,所以有些书说 一对k-v就是一个Entry
8.将Key放入Set类型的KeySet(HashMap$KeySet)中,
  将Value放入Collection类型的Values(HashMap$Values)中

源码剖析

package com.lcz.collection.map;


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

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      Map接口特点解读:
 *      1.k-v 最后是 HashMap$Node node = newNode(hash,key,value,null)
 *      2.k-v 为了方便程序员的遍历,还会创建一个 EntrySet集合,该集合存放的元素的类型是 Entry接口,
 *        而一个Entry接口对象就有k-v,EntrySet<Entry<k,v>>,即 transient Set<Map.Entry<K,V>> entrySet;
 *      3.entrySet 中,定义的类型是Set,存放元素的定义类型为Map.Entry<K,V>, 实际上存放的还是HashMap$Node(运行类型)
 *      4.当把 HashMap$Node 对象 存放到 entrySet 就方便我们的遍历,因为Map.Entry 提供了重要方法:
 *              K getKey(); V getValue();
 *      5.还会创建一个类型为Set的KeySet集合,存放的是K类型(Map对象的Key的类型)的Key,可以利用Set的三种遍历方式对键进行遍历
 *      6.还会创建一个类型为Collection的Values集合,存放的V类型(Map对象的Value的类型)的Value,可以利用Collection的三种遍历方式对值进行遍历
 *      7.KeySet、Values、entrySet都是HashMap的内部类,能作为集合是因为内部类实现了对应的集合接口
 *          注:都不是真正的存放,都是指向HashMap$Node相关信息!!!
 */
public class Map_ {
    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put("no1","lcz");
        map.put("no2","lhc");
        map.put(new Car1(),new Person());
        System.out.println(map);
        for (Object o :map.entrySet()) {
            Map.Entry entry = (Map.Entry) o;
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
        Set set1 = map.keySet();
        Collection set2 = map.values();
        System.out.println(set1);
        System.out.println(set2);
        for (Object o :set1) {
            System.out.println(o);
        }
        for (Object o :set2) {
            System.out.println(o);
        }


        System.out.println(set1.getClass());
        System.out.println(set2.getClass());
    }
}
class Car1{

}
class Person{

}

常用方法

1.put
2.remove
3.get
4.size
5.isEmpty
6.clear
7.containsKey

六种遍历方式

//六种遍历方式
        System.out.println("===六种遍历方式===");
        HashMap hashMap = new HashMap();
        hashMap.put("man","lcz");
        hashMap.put("woman","lhc");
        hashMap.put("cf角色","暗夜");
        //(1):先获取key,再根据key获取值
        Set set = hashMap.keySet();
        //1.1:迭代器
        System.out.println("1.1迭代器");
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            Object key =  iterator.next();
            System.out.println(key + "=" + hashMap.get(key));
        }
        //1.2增强for
        System.out.println("1.2增强for");
        for (Object key :set) {
            System.out.println(key + "=" + hashMap.get(key));
        }
        //(2):获取值
        //2.1:迭代器
        System.out.println("2.1:迭代器");
        Collection values = hashMap.values();
        Iterator iterator1 = values.iterator();
        while (iterator1.hasNext()) {
            Object value =  iterator1.next();
            System.out.println(value);
        }
        //2.2:增强for
        System.out.println("2.2:增强for");
        for (Object o :values) {
            System.out.println(o);
        }
        //(3):获取Entry接口对象,调用getKey和getValue方法获取键和值
        Set set3 = hashMap.entrySet();
        //3.1:迭代器
        System.out.println("3.1:迭代器");
        Iterator iterator2 = set3.iterator();
        while (iterator2.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator2.next();
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
        //3.2:增强for
        System.out.println("3.2:增强for");
        for (Object o :set3) {
            Map.Entry entry = (Map.Entry) o;
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }

Map接口练习题

Map接口练习题

package com.lcz.collection.map;

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

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      1.使用HashMap添加3个员工对象,要求:
 *          键:员工id
 *          值:员工对象
 *      2.并遍历显示工资大于18000的员工
 *      员工类:姓名、工资、id
 */
public class Exercise01 {
    public static void main(String[] args) {
        Map map = new HashMap();
        Emp lcz = new Emp("lcz", 30000, 1);
        Emp lhc = new Emp("lhc", 5000, 2);
        Emp lcq = new Emp("lcq", 20000, 3);
        map.put(lcz.getId(),lcz);
        map.put(lhc.getId(),lhc);
        map.put(lcq.getId(),lcq);
        Set set = map.keySet();
        for (Object key :set) {
            Emp emp = (Emp) (map.get(key));//map.get(key)返回的是Object类型,所以需要向下转型
            if(emp.getSal() > 18000)
                System.out.println(key + "=" + map.get(key));
        }

    }
}
class Emp{
    private String name;
    private double sal;
    private int id;

    public Emp(String name, double sal, int id) {
        this.name = name;
        this.sal = sal;
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", id=" + id +
                '}';
    }
}

HashMap类

底层机制结论

之前HashSet的底层就是它

1.HashMap底层维护了 Node 类型的数组table,默认为null
2.当创建对象时,将加载因子(loadfactor)初始化为0.75
3.当添加key-val时,将key的哈希值得到在table的索引,然后判断该索引处是否有元素,若没有,直接添加,若有,继续判断该元素的key和准备加入的key是否相等,若相等,则替换,若不相等,需要判断是树结构还是链表结构,做出相应处理,如果添加时发现容量达到临界值,需要扩容
4.第一次添加时,需要扩容table容量为16,临界值为12
5.以后再扩容,扩容table容量的2倍,临界值也变为26.在java8中,如果一条链表的元素个数超过TREEIFY_THRESHOLD,并且table的大小 >= MIN_TREEIFY_CAPACITY,就会进行树化(红黑树)

源码分析

package com.lcz.collection.map;

import java.util.HashMap;

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      HashMap源码解读
 *          跟HashSet源码相比:也就增加了个键相同,值替换的操作
 *          if (e != null) { // existing mapping for key
 *                 V oldValue = e.value;
 *                 if (!onlyIfAbsent || oldValue == null)//onlyIfAbsent = false
 *                     e.value = value;//进行值的替换
 *                 afterNodeAccess(e);
 *                 return oldValue;
 *             }
 */
public class HashMap_ {
    public static void main(String[] args) {
        HashMap hashMap = new HashMap();
        hashMap.put("man","lcz");
        hashMap.put("woman","lhc");
        hashMap.put("man","lcz");
        System.out.println(hashMap);


    }
}

HashMap小结

1.HashMap是以key-val对的方式来存储数据(HashMap$Node类型)
2.key不能重复,但值可以重复,允许使用null键和null3.如果添加相同的key,则会覆盖
4.无序,即不能保证映射的顺序,因为底层是以hash表的方式来存储的
5.HashMap没有实现同步,线程不安全

Hashtable

基本介绍

1.存放的元素是键值对:即K-V
2.键和值都不能为null,否则会抛出NullPointerException
3.使用方法基本和HashMap一样
4.Hashtable 是线程安全的(synchronized),HashMap是线程不安全的

源码解读

package com.lcz.collection.map.hashtable;

import java.util.Hashtable;

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      Hashtable类源码解读
 *          1.底层有数组 Hashtable$Entry[],初始化大小为 11
 *            临界值为 threshold = 8 (11*0.75)
 *            public Hashtable() {
 *               this(11, 0.75f);
 *             }
 *           this调用:
 *              this.loadFactor = loadFactor;
 *              table = new Entry<?,?>[initialCapacity];
 *              threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
 *          2.扩容:按照自己的扩容机制进行扩容
 *          3.执行方法 addEntry(hash,key,value,index);添加K-V,封装到Entry
 *          4.当if (count >= threshold) {
 *                              rehash();//进行扩容,扩容机制为:int newCapacity = (oldCapacity << 1) + 1;
 *                                                              (两倍+1)
 *          5.区别于HashMap:结点为Hashtable$Entry,为静态内部类Entry对象,此类实现Entry接口
 *                          仍有内部类KeySet,EntrySet,但Values变为ValueCollection,原理一样
 */ 
public class Hashtable_ {
    public static void main(String[] args) {
        Hashtable hashtable = new Hashtable();
        hashtable.put("no1","lcz");
        hashtable.put("no2","lhc");
        hashtable.put("no1","lcz");
        System.out.println(hashtable);
    }
}

Hashtable和HashMap对比

Hashtable和HashMap对比

Properties类

基本介绍

1.Properties类继承自Hashtable类并且实现了Map接口,也是使用一种键值对的形式来保存数据
2.特点和Hashtable类似
  不允许存放null值
3.Properties还可用于从 XXX.properties文件中,加载数据到Properties类对象,并进行读取和修改
4.XXX.properties 文件通常作为配置文件

基本使用

CRUD
增:put
删:remove
改:put
查:get
   getProperty

TreeSet类

基本介绍

1.实现Set接口的直接子类
1.当我们使用无参构造器,创建TreeSet时,仍然是无序的
2.若希望添加的元素,按照字符串大小进行排序
3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
  并指定排序规则
4.键和值都不能添加null值

源码解读

package com.lcz.collection.set.treeset;

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

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      TreeSet类特点:
 *      1.当我们使用无参构造器,创建TreeSet时,仍然是无序的
 *      2.若希望添加的元素,按照字符串大小进行排序
 *      3.使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)
 *         并指定排序规则
 *      源码解读:
 *      TreeSet的底层就是TreeMap
 *      1.构造器把传入的比较器对象,赋给了TreeSet的底层的TreeMap的属性 this.comparator
 *          public TreeMap(Comparator<? super K> comparator) {
 *              this.comparator = comparator;
 *          }
 *      2.在调用 treeSet.add("jack") 底层会执行到
 *          if (cpr != null) {//cpr就是我们的匿名内部类对象
 *             do {
 *                 parent = t;
 *                 cmp = cpr.compare(key, t.key);//动态绑定到我们的匿名内部类(对象)的compare
 *                 if (cmp < 0)
 *                     t = t.left;
 *                 else if (cmp > 0)
 *                     t = t.right;
 *                 else//如果相等,即返回0,这个key就加入失败
 *                     return t.setValue(value);
 *             } while (t != null);
 *         }
 */
public class TreeSet_ {
    public static void main(String[] args) {
        //TreeSet treeSet = new TreeSet();
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //return ((String)o1).compareTo(((String)o2));
                return ((String)o1).length() - ((String)o2).length();
            }
        });
        treeSet.add("jack");
        treeSet.add("lhc");
        treeSet.add("it");
        treeSet.add("a");
        //treeSet.add(null);
        System.out.println(treeSet);
    }
}

TreeMap类

基本介绍

同TreeSet类
1.实现Map接口的直接子类
2.当我们使用无参构造器,创建TreeMap时,仍然是无序的
3.若希望添加的元素,按照字符串大小进行排序
  使用TreeMap提供的一个构造器,可以传入一个比较器(匿名内部类)
  并指定排序规则
4.键和值都不能添加null值

源码解读

package com.lcz.collection.map.treemap;

import java.util.Comparator;
import java.util.TreeMap;

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      TreeMap类源码解读:
 *      1.当我们使用无参构造器,创建TreeMap时,仍然是无序的
 *      2.构造器把传入的比较器对象,赋给了TreeSet的底层的TreeMap的属性 this.comparator
 *          public TreeMap(Comparator<? super K> comparator) {
 *              this.comparator = comparator;
 *          }
 *      3.调用put方法
 *      3.1第一次添加
 *          if (t == null) {
 *             compare(key, key); // type (and possibly null) check
 *
 *             root = new Entry<>(key, value, null);
 *             size = 1;
 *             modCount++;
 *             return null;
 *         }
 *      3.2以后添加
 *          Comparator<? super K> cpr = comparator;
 *         if (cpr != null) {
 *             do {//遍历所有key,给当前key找到合适位置
 *                 parent = t;
 *                 cmp = cpr.compare(key, t.key);//动态绑定到我们的匿名内部类对象的compare
 *                 if (cmp < 0)
 *                     t = t.left;
 *                 else if (cmp > 0)
 *                     t = t.right;
 *                 else//如果相等,则返回0,不添加
 *                     return t.setValue(value);
 *             } while (t != null);
 *         }
 */
public class TreeMap_ {
    public static void main(String[] args) {
        TreeMap treeMap = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //return ((String)o1).compareTo(((String)o2));
                return ((String)o2).length() - ((String)o1).length();
            }
        });
        treeMap.put("jack","a");
        treeMap.put("lhc","b");
        treeMap.put("it","c");
        treeMap.put("a","d");
        //treeMap.put(null,'a');
        //treeMap.put("z",null);
        System.out.println(treeMap);
    }
}

集合选型规则

取决于业务操作特点,然后根据集合实现类特性进行选择

1)先判断存储的类型(一组对象[单列]或一组键值对[双列])
2)一组对象[单列]:Collection接口
	允许重复:List
		增删多:LinkedList[底层维护了一个双向链表]
		改查多:单线程:ArrayList[底层维护Object类型的可变数组]
    		   多线程:Vector
	不允许重复:Set
		无序:HashSet[底层是HashMap,维护了一个哈希白哦,即(数组+链表+红黑树)]
		排序:TreeSet
		插入和取出顺序一致:LinkedHashSet(底层是LinkedHashMap,而其底层又为							HashMap),维护数组+双向链表
3)一组键值对[双列]Map
	键无序:单线程:HashMap[底层是:哈希表 jdk7:数组+链表,jdk8:数组+链表+红黑																   树]
    	   多线程:Hashtable
	键排序:TreeMap
	键插入和取出顺序一致:LinkedHashMap
	读取文件:Properties

Collections工具类

介绍

1.是一个操作Set、List、Map等集合的工具类
2.提供了一系列静态的方法对集合元素进行排序、查询和修改等操作

常用方法

  • reverse(List):反转List中元素的顺序
  • shuffle(List):对List集合元素进行随机排序
  • sort(List):根据元素的自然顺序对指定List集合元素按升序排序
  • sort(List,Comparator):根据指定的比较器产生的顺序进行排序
  • swap(List,int,int):将指定List集合中的 i 处元素和 j 处元素进行交换

查找替换

  • Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
  • Object max(Collection,Comparator):根据比较器指定的顺序,返回给定集合最大元素
  • Object min(Collection)
  • Object min(Collection,Comparator)
  • int frequency(Collection,Object):返回指定集合中指定元素的出现次数
  • void copy(List dest,List src):将src的内容复制到dest中
  • boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List对象的所有旧值

演示

package com.lcz.collection.collections;

import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      Collections工具类常用方法
 */
public class Collections_ {
    public static void main(String[] args) {
//        - reverse(List):反转List中元素的顺序
        ArrayList arrayList = new ArrayList();
        arrayList.add("a");
        arrayList.add("b");
        arrayList.add("c");
        arrayList.add("d");
        System.out.println("翻转前");
        System.out.println(arrayList);
        Collections.reverse(arrayList);
        System.out.println("翻转后");
        System.out.println(arrayList);
//        - shuffle(List):对List集合元素进行随机排序
        Collections.shuffle(arrayList);
        System.out.println("随机排序");
        System.out.println(arrayList);
//        - sort(List):根据元素的自然顺序对指定List集合元素按升序排序
        //自然顺序:指按字符串大小
        Collections.sort(arrayList);
        System.out.println("自然排序升序后");
        System.out.println(arrayList);
//        - sort(List,Comparator):根据指定的比较器产生的顺序进行排序
        Collections.sort(arrayList, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length() - ((String)o2).length();
            }
        });
        System.out.println("按照字符串大小从小到大");
        System.out.println(arrayList);
//        - swap(List,int,int):将指定List集合中的 i 处元素和 j 处元素进行交换
        Collections.swap(arrayList,0,1);
        System.out.println("交换后");
        System.out.println(arrayList);
//
//        查找替换
//        - Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
        System.out.println("自然顺序最大值");
        System.out.println(Collections.max(arrayList));
//        - Object max(Collection,Comparator):根据比较器指定的顺序,返回给定集合最大元素
        System.out.println("字符串长度大小最大值");
        System.out.println(Collections.max(arrayList, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length() - ((String)o2).length();
            }
        }));
//        - Object min(Collection)
//        - Object min(Collection,Comparator)
//        - int frequency(Collection,Object):返回指定集合中指定元素的出现次数
        System.out.println("指定元素a出现次数");
        System.out.println(Collections.frequency(arrayList,"a"));
//        - void copy(List dest,List src):将src的内容复制到dest中
        ArrayList arrayList1 = new ArrayList(10);
        //设置初始容量为10,仍报异常,因为list是在第一次添加元素时,才创建底层的数组,之前数组为null
        arrayList1.add("asdfas");
        arrayList1.add("ljil");
        Collections.copy(arrayList,arrayList1);
        System.out.println("复制后");
        System.out.println(arrayList);//可能会报异常:因为要求dest长度大于src长度,长度指元素个数
//        - boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List对象的所有旧值
        Collections.replaceAll(arrayList,"c","lcz");
        System.out.println("替换后");
        System.out.println(arrayList);
    }
}

本章作业

作业1

package com.lcz.collection.homework;

import java.util.ArrayList;

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      1.封装一个新闻类:包含标题和内容属性,提供get、set方法,重写toString方法,
 *        打印对象时只打印标题
 *      2.只提供一个带参数的构造器,实例化对象时,只初始化标题
 *      新闻一:新冠确诊病例超千万,数百万印度教信徒负桓河”圣域“因民众担忧
 *      新闻二:男子突然想起2各月前调的鱼经还在鱼兜里面,捞起一看赶紧放生!
 *      3.将新闻对象添加到ArrayList集合中,并且进行倒序遍历;
 *      4.在遍历集合过程中,对新闻标题进行处理,超过15个字的只保留前15个,在后面加”...“
 *      5.在控制台打印遍历出经过处理的新闻标题
 */
public class Homework01 {
    public static void main(String[] args) {
        News news = new News("新冠确诊病例超千万,数百万印度教信徒负桓河”圣域“因民众担忧");
        News news1 = new News("男子突然想起2各月前调的鱼经还在鱼兜里面,捞起一看赶紧放生!");
        ArrayList arrayList = new ArrayList();
        arrayList.add(news);
        arrayList.add(news1);
        for (int i = arrayList.size()-1; i >= 0; i--) {//调用处理title的方法,然后输出处理后的title
            News temp = (News) (arrayList.get(i));
            System.out.println(processTitle(temp.getTitle()));
        }
    }
    public static String processTitle(String title){//将对title进行处理单独封装为一个方法去实现
        if(title == null)
            return "";
        if (title.length() > 15)
            return title.substring(0,16) + "...";
        else
            return title;
    }
}
class News{
    private String title;
    private String content;

    public News(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

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

作业2

package com.lcz.collection.homework;

import java.util.*;

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      1.使用HashMap类实例化一个Map类型的对象m,键(String)和值(int) 分别用于存储员工的姓名和工资,存入数据如下:
 *          jack——650元
 *          tom——1200元
 *          smith——2900元
 *      2.将jack的工资更改为2600元
 *      3.为所有员工工资加薪1000元
 *      4.遍历集合中所有的员工
 *      5.遍历集合中所有的工资
 */
public class Homework02 {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("jack",650);
        map.put("tom",1200);
        map.put("smith",2900);
        map.put("jack",2600);
        Set entrySet = map.entrySet();
        System.out.println("遍历所有员工:");
        System.out.println("增强for:");
        for (Object o :entrySet) {
            Map.Entry entry = (Map.Entry) o;
            System.out.println("员工姓名:" + entry.getKey() + ",员工工资:" + entry.getValue());
        }
        System.out.println("迭代器:");
        Iterator iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            Map.Entry entry =  (Map.Entry) iterator.next();
            System.out.println("员工姓名:" + entry.getKey() + ",员工工资:" + entry.getValue());
        }
        Collection values = map.values();
        System.out.println("遍历所有工资:");
        for (Object o :values) {
            System.out.println("工资:" + o);
        }


    }
}

作业3

package com.lcz.collection.homework;

/**
 * @author lcz
 * @version 1.0
 * 需求;
 *      试分析HashSet和TreeSet分别如何实现去重的
 *      (1):HashSet的去重机制:hashCode() + equals(),底层先通过存入一个对象,进行运算得到一个hash值,
 *          再根据hash值进行运算得到对应的索引,如果发现table索引所在的位置,没有数据,就直接存放,
 *          如果有数据,就进行equals循环比较(for遍历链表),如果比较后,不相同,就加入,否则不加入
 *      (2):TreeSet的去重机制:如果你传入一个Comparator匿名对象,就使用实现的compare方法去重,如果方法返回0,
 *          就认为是相同的数据元素,就不添加。
 *          如果你没有传入一个Comparator匿名对象,则以你添加的对象实现Compareable接口的compareTo去重
 */
public class Homework03 {
}

作业4

package com.lcz.collection.homework;

import java.util.TreeSet;

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      分析代码是否报错
 *      会报ClassCastException(类型转换错误)
 *      原因:
 *          1.因为未传入一个comparator匿名对象
 *          2.则会根据添加的对象实现Comparable接口的compareTo方法进行去重
 *          3.而Person未实现Coparable接口,所以将添加对象转化为Comparable接口类型时报错
 */
public class Homework04 {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        treeSet.add(new Person());
    }
}
class Person{

}

作业5

作业5

p1.name = "CC",
内容更改,计算出的hash值和对应的索引都会变,也就是删除p1失败
添加 1001 "CC" 成功
添加 1001 "AA" 成功

作业6作业6

try = (Map.Entry) o;
System.out.println(“员工姓名:” + entry.getKey() + “,员工工资:” + entry.getValue());
}
System.out.println(“迭代器:”);
Iterator iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
System.out.println(“员工姓名:” + entry.getKey() + “,员工工资:” + entry.getValue());
}
Collection values = map.values();
System.out.println(“遍历所有工资:”);
for (Object o :values) {
System.out.println(“工资:” + o);
}

}

}


作业3

```java
package com.lcz.collection.homework;

/**
 * @author lcz
 * @version 1.0
 * 需求;
 *      试分析HashSet和TreeSet分别如何实现去重的
 *      (1):HashSet的去重机制:hashCode() + equals(),底层先通过存入一个对象,进行运算得到一个hash值,
 *          再根据hash值进行运算得到对应的索引,如果发现table索引所在的位置,没有数据,就直接存放,
 *          如果有数据,就进行equals循环比较(for遍历链表),如果比较后,不相同,就加入,否则不加入
 *      (2):TreeSet的去重机制:如果你传入一个Comparator匿名对象,就使用实现的compare方法去重,如果方法返回0,
 *          就认为是相同的数据元素,就不添加。
 *          如果你没有传入一个Comparator匿名对象,则以你添加的对象实现Compareable接口的compareTo去重
 */
public class Homework03 {
}

作业4

package com.lcz.collection.homework;

import java.util.TreeSet;

/**
 * @author lcz
 * @version 1.0
 * 需求:
 *      分析代码是否报错
 *      会报ClassCastException(类型转换错误)
 *      原因:
 *          1.因为未传入一个comparator匿名对象
 *          2.则会根据添加的对象实现Comparable接口的compareTo方法进行去重
 *          3.而Person未实现Coparable接口,所以将添加对象转化为Comparable接口类型时报错
 */
public class Homework04 {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        treeSet.add(new Person());
    }
}
class Person{

}

作业5
在这里插入图片描述

p1.name = "CC",
内容更改,计算出的hash值和对应的索引都会变,也就是删除p1失败
添加 1001 "CC" 成功
添加 1001 "AA" 成功

作业6
在这里插入图片描述

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值