-
List 、Set 、Map 三者着重点(区别)
List | 集合有顺序、可以有重复对象 |
Set | 集合不允许重复的对象 |
Map | 用键值对存储 & 通过key搜索、 key可以是任何对象 & key不可以重复、 两个key可以引用相同的对象 |
- =。= 排不到一起的列表...
-
ArrayList & LinkedList
ArrayList LinkedList 线程安全? 都不安全、都不同步 底层数据结构是什么? 数组 Object[] 双向链表 LinkedList.Node<E> 插入、删除是否受元素位置影响? 数组存储,受影响 链表存储,指定位置插入受影响,没指定不受元素位置的影响 是否支持快速随机访问? 支持,通过get(int index) 不支持 内存空间占用 列表结尾预留一定的容量空间 每个元素消耗更多的空间,存放直接前驱、直接后继、数据 ArrayList Vector 底层 数组存储 数组存储 线程安全? 不是同步,不需要保证线程安全时建议使用ArrayList. 所有方法都是同步的,线程安全
但是一个线程访问要在同步操作上耗费大量时间 -
HashMap & HashTable 区别
HashMap HashTable 底层数据结构? 数组+链表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的幂次方大小
-
HashMap & HashSet 区别
HashMap HashSet 底层? 数组+链表Node<K,V> [散列链表]
jdk1.8之后变成 数组+链表+红黑树
HashSet的底层是 基于HashMap 实现的 实现的接口? 实现了Map接口 实现了Set接口 存储的东西 存储键值对 仅存储对象 添加元素方法? put(...) add(...) 如何计算Hashcode? 使用键Key计算Hashcode 使用成员对象计算HashCode -
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 ?