【Java基础】笔记
List和ArrayList区别
public class Arrays_BugDemo
{
public static void main(String[] args)
{
/*
* List 是一个固定大小的列表,虽然可以进行查询操作,但不支持添加、删除或修改元素。
* 如果需要一个可以动态修改的列表,可以使用 ArrayList 进行包装。
*/
// 如果初始化后,还是要进行动态修改,可以外面包一层New ArrayList
List<Integer> list = new ArrayList<>( Arrays.asList(1, 2));
//相当于New一个list 将元素1跟2封装进这个list集合中
// List<Integer> list = Arrays.asList(1, 2);
list.add(3); // 给list添加数据报错
list.forEach(System.out::println);
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(232);
arrayList.add(2324);
arrayList.forEach(System.out::println);
}
}
直接对List进行添加元素,会报错不支持该操作异常,原因:
阿里巴巴Java开发规范,使用工具类 Arrays.asList() 方法把数组转换成集合时,不能使用其修改集合相关的方法。
因为它的 add/remove/clear 方法会抛出 UnsupportedOperationException() 本质上的原因是因为List列表是固定大小的,不能够进行动态修改。
Arrays.ArrayList类继承自AbstractList,实现了List接口。它重写了add()、remove()等修改List结构的方法,并将它们直接抛出UnsupportedOperationException异常,从而禁止了对List结构的修改。
具体来说,Arrays.asList()方法返回的是Arrays类中的一个私有静态内部类ArrayList,它继承自AbstractList类,实现了List接口。
迭代器遍历时,不能动态修改
public class IteratorRemoveDemo
{
public static void main(String[] args)
{
List<Integer> list = new ArrayList<>();
list.add(11);
list.add(12);
list.add(13);
list.add(14);
list.add(15);
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext())
{
Integer value = iterator.next();
if(value == 12)
{
// 在迭代过程中,不允许修改集合元素,否则会抛出异常。
//list.remove(value); //Exception in thread "main" java.util.ConcurrentModificationException
// 使用迭代器的 remove() 方法删除元素
iterator.remove();
}
}
list.forEach(v -> System.out.println(v));
}
}
报错:并发修改异常,遍历时迭代器进行了动态修改
这里可以看出,通过迭代器Iterator
中的next()
方法中有一个checkForComodification();
方法,在每次调用 next() 方法时,迭代器会检查 modCount
是否等于 expectedModCount
。
如果不相等,说明在遍历过程中 ArrayList 被修改过,迭代器会抛出 ConcurrentModificationException
异常。
- modCount :AbstractList类中的一个成员变量,由于ArrayList继承自AbstractList,ArrayList中的modCount变量也继承过来了。 modCount 记录了 ArrayList 从创建以来对其结构进行的修改次数,这里的“结构修改”指的是添加、删除元素,不包括修改
- expectedModCount : 就是迭代器期望的修改次数,用于记录在创建迭代器时ArrayList的modCount值。在创建得迭代器的时候,expectedModCount 的值就是modCount的值。
Hash冲突
public class HashCode {
static class stu {
}
public static void main(String[] args) {
HashSet<Integer> hashSet = new HashSet<>();
for (int i = 1; i < 15*10000; i++) {
int stuCode = new stu().hashCode();
// 检查HashSet中是否已存在当前学生的哈希码
if(!hashSet.contains(stuCode)){ // 如果HashSet中没有该哈希码,则添加
hashSet.add(stuCode);
}else{ // 如果HashSet中已存在该哈希码,则视为哈希冲突
System.out.println("发生了hash冲突,在第:"+i+"次的hash值为:"+stuCode);
}
}
// 打印HashSet的大小,即不重复的哈希码数量
System.out.println(hashSet.size());
}
}
哈希冲突的原因
- 哈希码范围有限:哈希码通常是固定长度的整数,而对象数量可能远超这个范围。
- 哈希函数设计:即使设计良好,哈希函数也无法完全避免产生相同的哈希码。
- 数据特性:某些数据集可能导致哈希码更集中,增加冲突概率。