笔记1——Java集合框架(List、Set、Map) & 哈希

  1. List 、Set 、Map 三者着重点(区别)

List集合有顺序、可以有重复对象
Set集合不允许重复的对象
Map

键值对存储 & 通过key搜索、

key可以是任何对象 & key不可以重复

两个key可以引用相同的对象

  1. =。=  排不到一起的列表...
  2. ArrayList & LinkedList 

    ArrayListLinkedList
    线程安全?都不安全、都不同步
    底层数据结构是什么?数组 Object[]双向链表  LinkedList.Node<E>
    插入、删除是否受元素位置影响?数组存储,受影响链表存储,指定位置插入受影响,没指定不受元素位置的影响
    是否支持快速随机访问?支持,通过get(int index)不支持
    内存空间占用列表结尾预留一定的容量空间每个元素消耗更多的空间,存放直接前驱、直接后继、数据
    ArrayListVector
    底层数组存储数组存储
    线程安全?不是同步,不需要保证线程安全时建议使用ArrayList.所有方法都是同步的,线程安全
    但是一个线程访问要在同步操作上耗费大量时间

  3. HashMap & HashTable 区别

    HashMapHashTable
    底层数据结构?数组+链表Node<K,V>  [散列链表
     jdk1.8之后变成 数组+链表+红黑树
    数组+Entry<K,V>
    [默认初始容量 = 16]
    [底层树化标准元素个数是 8,树化的阈值,当个数大于8,就转化为红黑树]
    [默认初始容量 = 11,负载系数 = 0.75]
    是否线程安全?线程不安全、不同步线程不安全、不同步
    效率?比较快,因为不用同步效率比较低,因为线程安全、同步,基本被淘汰,不用.
    对Null key 和 Null value 的支持

    key可以为null,只有一个;value可以为null

    [ps:key为null时,Node的hash值通过判断设为0]

    key、value都不可以为空.

    [ps:value为空直接判断抛空指针异常,key为null,hashCode()获取hash值抛异常]

    初始容量大小?

    每次扩充容量大小?

    不指定时初始容量为16;每次扩充,容量变为2倍

    指定初始大小,指定多大就是多大

    不指定时初始容量为11;每次扩充,容量变为2n+1

    指定初始大小,扩充为2的幂次方大小

  4. HashMap & HashSet 区别

    HashMapHashSet
    底层?

    数组+链表Node<K,V>  [散列链表] 

    jdk1.8之后变成 数组+链表+红黑树

    HashSet的底层是 基于HashMap 实现的
    实现的接口?实现了Map接口实现了Set接口
    存储的东西存储键值对仅存储对象
    添加元素方法?put(...)add(...)
    如何计算Hashcode?使用键Key计算Hashcode使用成员对象计算HashCode
  5. HashMap如何去存储?如何将数据放到数组和链表上?
    答案:哈希算法。                         

转而看向[ 哈希表 ] 相关:
Hashtable[数据结构] >>> Java中实现该结构的类是[HashTable类],java的hashtable实现了同步导致性能问题.>>>>> 一般,用Java的[HashMap类]代替使用,HashMap没有同步.

5.1 什么是哈希表?  哈希表是一种数据结构,数据以 数组 格式存储,数据组有唯一的键值.
5.2 什么是哈希 hash ? 将Object映射成一组字符(代码)的规则,通常是将一大块数据转换成一个小的整数值。
5.3 哈希码的作用:确定一个对象在哈希表中的索引位置。​​​​​​​
5.4 哈希函数特性:
1) 特定对象具有特定哈希码
2) 相等的对象具有相同的哈希码,相同的哈希码不一定是相等的对象
3) 不同的哈希码,对象肯定不相等
4) 不同的对象可能具有相同的哈希码。这种非常罕见的事件称为碰撞。好的散列函数将冲突的可能性降至最低。
PS : 散列表 = 哈希表 ,散列函数 = 哈希函数 hash function
5.5 hashCode() 和 equals() 之间的关系:
1) 对象相等,hashcode相等
2) 对象相等,equals()返回true.  但是,equals()才能真正判断相等与否
3) 两个对象有相同的hashcode,不一定相等.
4) 因此,equals()覆盖,则 hashCode()也必须覆盖
5) hashCode()默认行为是对堆上的对象产生独特值。如果没有重写,会导致无论如何都不相等.
5.6 为什么 重写 equals()的时候,必须重写 hashCode()方法?
1) 必须在每个覆盖 equals() 的类中覆盖 hashCode(), 不这样做将导致违Object.hashCode() 的一般契约, 这将阻止您的类与所有基于哈希的集合(包括 HashMap、HashSet 和 Hashtable)一起正常运行。
[一般契约 ——“如果两个对象使用 Object class equals 方法相等,那么 hashcode 方法应该为这两个对象提供相同的值。”]
2) 只重写equals():两个对象会散列到不同的桶 [不是很明白这句~存储桶、哈希桶]
    ​​​​​PS:当我们将对象存储在存储桶中时处理数据结构(存储桶是文件夹的一个奇特名称),如果我们使用内置哈希技术,对于两个对象,它会生成两个不同的哈希码, 所以我们在两个不同的地方存储相同的对象。为避免此类问题,我们还应根据以下原则覆盖 hashCode 方法。
     不相等的实例可能具有相同的哈希码。
     相等的实例应该返回相同的哈希码。

从代码来看好像更好理解 (●'◡'●) :先建几个类如下,当age和name 都相同的时候 则对象相等。然后运行TestApplication看结果。

Person.没有重写equals、没有重写hashCode 
PersonOverEquals.重写equals、没有重写hashCode
PersonOverHash.没有重写equals,只重写hashCode
PersonOverride.重写equals、重写hashCode 
public class Person {

    private String name;
    private int age;

    public Person(String nameVal,int ageVal){
        name = nameVal ;
        age = ageVal;
    }

}
/**
 * 只重写equals(): age和name 都相同时为true
 */
public class PersonOverEquals {

    private String name;
    private int age;


    public PersonOverEquals(String nameVal,int ageVal){
        name = nameVal ;
        age = ageVal;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PersonOverEquals that = (PersonOverEquals) o;
       // System.out.println("    >>:PersonOverEquals类,equals值 :  " + (age == that.age && name.equals(that.name)));
        return age == that.age && name.equals(that.name);
    }


}
import java.util.Objects;
/**
 * 只重写 hashCode()
 */
public class PersonOverHash {

    private String name;
    private int age;


    public PersonOverHash(String nameVal,int ageVal){
        name = nameVal ;
        age = ageVal;
    }


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

import java.util.Objects;

/**
 * 重写 hashCode()、equals()
 */
public class PersonOverride {
    private String name;
    private int age;

    public PersonOverride(String nameVal,int ageVal){
        name = nameVal ;
        age = ageVal;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PersonOverride that = (PersonOverride) o;
       // System.out.println("    >>:PersonOverride类,equals值 :  " + (age == that.age && name.equals(that.name)));
        return age == that.age && name.equals(that.name);
    }

    @Override
    public int hashCode() {
        int hashCodeVal = Objects.hash(name, age);
       // System.out.println("    >>:PersonOverride类,hashCodeVal :  "+hashCodeVal);
        return hashCodeVal;

    }
}
public class TestApplication {

    public static void main(String[] args) {
        System.out.println("1.没有重写equals、没有重写hashCode");
        testPerson();
        System.out.println("");
        System.out.println("2.重写equals、没有重写hashCode");
        testPersonOverEquals();
        System.out.println("");
        System.out.println("3.重写equals、重写hashCode");
        testPersonOverride();
        System.out.println("");
        System.out.println("4.没有重写equals,只重写hashCode");
        testPersonOverHash();

    }



    public static void testPerson(){
        Person person1 = new Person("张三",20);
        Person person2 = new Person("李四",18);
        Person person3 = new Person("李四",18);
        System.out.println("person1: "+person1.hashCode());
        System.out.println("person2: "+person2.hashCode());
        System.out.println("person3: "+person3.hashCode());
        System.out.println("person1 = person2 ? "+person1.equals(person2));
        System.out.println("person2 = person3 ? "+person2.equals(person3));

    }

    public static void testPersonOverEquals(){
        PersonOverEquals person1 = new PersonOverEquals("张三",20);
        PersonOverEquals person2 = new PersonOverEquals("李四",18);
        PersonOverEquals person3 = new PersonOverEquals("李四",18);
        System.out.println("person1: "+person1.hashCode());
        System.out.println("person2: "+person2.hashCode());
        System.out.println("person3: "+person3.hashCode());
        System.out.println("person1 = person2 ? "+person1.equals(person2));
        System.out.println("person2 = person3 ? "+person2.equals(person3));

    }

    public static void testPersonOverride(){
        PersonOverride person1 = new PersonOverride("张三",20);
        PersonOverride person2 = new PersonOverride("李四",18);
        PersonOverride person3 = new PersonOverride("李四",18);
        System.out.println("person1: "+person1.hashCode());
        System.out.println("person2: "+person2.hashCode());
        System.out.println("person3: "+person3.hashCode());
        System.out.println("person1 = person2 ? "+person1.equals(person2));
        System.out.println("person2 = person3 ? "+person2.equals(person3));

    }


    public static void testPersonOverHash(){
        PersonOverHash person1 = new PersonOverHash("张三",20);
        PersonOverHash person2 = new PersonOverHash("李四",18);
        PersonOverHash person3 = new PersonOverHash("李四",18);
        System.out.println("person1: "+person1.hashCode());
        System.out.println("person2: "+person2.hashCode());
        System.out.println("person3: "+person3.hashCode());
        System.out.println("person1 = person2 ? "+person1.equals(person2));
        System.out.println("person2 = person3 ? "+person2.equals(person3));

    }


}

运行结果如下图~2.的运行结果,person2和person3 这个时候age、name都相同, equals()判断是相同的,但是由于没有重写hashCode(),导致person2、person3的哈希值不同,这违反了Java对于hashcode的一般约定。看看3.的结果,person2、person3相等,equals()结果为true,hashcode也相同。符合Java对于相等的对象,哈希码相同。

最后,看一眼,Objects类的hash(...)方法:

 最后的最后,我的学习来源:(●'◡'●)

javaGuide全网阅读过20k的Java集合框架常见面试题总结!

What is Hashtable? Java Hashtable with examples
Why do I need to override the equals and hashCode methods in Java?
​​​​​​​​​​​​​​Why to Override equals(Object) and hashCode() method ?
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值