3. Collection<? extends E>型构造方法
源码剖析
/**
-
Constructs a list containing the elements of the specified
-
collection, in the order they are returned by the collection’s
-
iterator.
-
@param c the collection whose elements are to be placed into this list
-
@throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
// 将参数中的集合转换为数组,赋值给 elementData
elementData = c.toArray();
// 如果数组的大小不等于 0
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
// 如果c.toArray()返回的数组类型不是Object[]类型的
// 则利用Arrays.copyOf()创建一个大小为size的、类型为Object[]的数组, 并将elementData中的元素复制到新的数组中
// 最后让elementData 指向新的数组
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else { // 否则设置元素数组为空数组
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
总结:
-
将参数中的集合转换为数组,赋值给 elementData
-
.给size进行赋值,size代表集合元素数量。判断参数是否为空,如果数组的大小不等于 0,则进一步判断是否转化为Object类型的数组,如果不是,则进行复制;
-
否则,设置元素数组为空数组
三、常用方法及其源码剖析
1. get()方法
get(int index)
方法是返回集合中指定位置的元素。
源码剖析
/**
-
Returns the element at the specified position in this list.
-
@param index index of the element to return
-
@return the element at the specified position in this list
-
@throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
// 检查下标索引是否越界
rangeCheck(index);
// 返回指定索引处的值
return elementData(index);
}
- 首先会检查索引值是否越界,如果索引值大于数组大小,则会抛出异常。
源码如下:
private void rangeCheck(int index) {
// 索引值大于数组大小
if (index >= size)
// 抛出异常
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
- 如果所引是合法的,则调用elementData(int index)方法获取指定位置的元素。
2. set() 方法
set(int index, E element)
方法将index索引处的元素替换成element对象,返回被替换的旧元素。
源码剖析
/**
-
Replaces the element at the specified position in this list with
-
the specified element.
-
@param index index of the element to replace
-
@param element element to be stored at the specified position
-
@return the element previously at the specified position
-
@throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
// 检查下标索引是否越界
rangeCheck(index);
// 指定下标处的旧值
E oldValue = elementData(index);
// 指定下标处赋新的值
elementData[index] = element;
// 返回旧值
return oldValue;
}
3. add() 方法
add(E e)
方法 将指定的元素追加到此集合的末尾
源码剖析
/**
-
Appends the specified element to the end of this list.
-
@param e element to be appended to this list
-
@return true (as specified by {@link Collection#add})
*/
public boolean add(E e) {
// 插入元素之前,会检查是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
// 将元素添加到数组中最后一个元素的后面,最后将集合中实际的元素个数加 1
elementData[size++] = e;
return true;
}
add(int index, E element)
在集合元素序列 index 位置处插入
源码剖析
/**
-
Inserts the specified element at the specified position in this
-
list. Shifts the element currently at that position (if any) and
-
any subsequent elements to the right (adds one to their indices).
-
@param index index at which the specified element is to be inserted
-
@param element element to be inserted
-
@throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
// 检查下标索引是否越界
rangeCheckForAdd(index);
// 插入元素之前,会检查是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
// 将 index 位置及其后面的所有元素都向后移一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// 将新元素插入到 index 位置处,元素个数加 1
elementData[index] = element;
size++;
}
4. remove() 方法
remove(int index)
方法是删除该集合中指定位置的元素
源码剖析
/**
-
Removes the element at the specified position in this list.
-
Shifts any subsequent elements to the left (subtracts one from their
-
indices).
-
@param index the index of the element to be removed
-
@return the element that was removed from the list
-
@throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
// 检查下标索引是否越界
rangeCheck(index);
modCount++;
// 返回被删除的元素值
E oldValue = elementData(index);
// 需要移动的元素的个数
int numMoved = size - index - 1;
if (numMoved > 0)
// 将 index + 1 及其后面的元素向前移动一位,覆盖被删除的元素值
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 把数组最后一个元素赋值为null,将元素个数减一
elementData[–size] = null; // clear to let GC do its work
// 返回旧值
return oldValue;
}
remove(Object o)
方法是删除指定的元素,如果有重复的元素,则只会删除下标最小的元素
源码剖析
/**
-
Removes the first occurrence of the specified element from this list,
-
if it is present. If the list does not contain the element, it is
-
unchanged. More formally, removes the element with the lowest index
-
i such that
-
(o==null ? get(i)==null : o.equals(get(i)))
-
(if such an element exists). Returns true if this list
-
contained the specified element (or equivalently, if this list
-
changed as a result of the call).
-
@param o element to be removed from this list, if present
-
@return true if this list contained the specified element
*/
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
// 遍历数组,查找要进行删除元素的位置
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
fastRemove(int index)
方法是快速删除,删除跳过边界检查的方法,也不返回删除的元素值
源码剖析
/*
-
Private remove method that skips bounds checking and does not
-
return the value removed.
*/
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[–size] = null; // clear to let GC do its work
}
5. size() 方法
返回集合中的元素个数
源码剖析
/**
-
Returns the number of elements in this list.
-
@return the number of elements in this list
*/
public int size() {
return size;
}
6. indexOf(Object o) 方法
返回对象o在集合中第一次出现的位置的索引
源码剖析
/**
-
Returns the index of the first occurrence of the specified element
-
in this list, or -1 if this list does not contain the element.
-
More formally, returns the lowest index i such that
-
(o==null ? get(i)==null : o.equals(get(i))),
-
or -1 if there is no such index.
*/
public int indexOf(Object o) {
// 如果查找的元素为空
if (o == null) {
// 循环遍历数组
for (int i = 0; i < size; i++)
// 如果 i 位置的原素为空
if (elementData[i]==null)
// 返回下标
return i;
// 否则,查找的元素不为空
} else {
// 循环遍历数组
for (int i = 0; i < size; i++)
// 找到第一个和要查找的元素相等的元素
if (o.equals(elementData[i]))
// 返回下标
return i;
}
// 返回 -1.则表示没有找到
return -1;
}
四、ArrayList 和 Vector 的区别
-
ArrayList 和 Vector 底层都是 数组
-
ArrayList 每次扩容的情况下扩容为原来的1.5 倍。线程不安全,当多个线程同时访问同一个ArrayList 集合时,如果两个或两个以上的线程修改了 ArrayList 集合,则必须手动保证该集合的同步性。
-
Vector 是同步类,其线程安全,但是它的访问比较慢。Vector 每次扩容为其空间大小的 2 倍。
五、对扩容原理源码剖析及其思考
- 在add()方法中调用ensureCapacityInternal()方法,用来确保添加元素的时候,最小容量是 minCapacity。
源码剖析
private void ensureCapacityInternal(int minCapacity) {
// 判断元素数组是否为空数组
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 取最大值
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
- 在ensureCapacityInternal()方法里面调用ensureExplicitCapacity(int minCapacity)方法,用来判段集合在添加元素的时候是否需要对当前的数组进行扩容。
源码剖析
private void ensureExplicitCapacity(int minCapacity) {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
![img](https://i-blog.csdnimg.cn/blog_migrate/1a2ebe72313ed0e3cb936720c7692397.jpeg)
最后的内容
在开头跟大家分享的时候我就说,面试我是没有做好准备的,全靠平时的积累,确实有点临时抱佛脚了,以至于我自己还是挺懊恼的。(准备好了或许可以拿个40k,没做准备只有30k+,你们懂那种感觉吗)
如何准备面试?
1、前期铺垫(技术沉积)
程序员面试其实是对于技术的一次摸底考试,你的技术牛逼,那你就是大爷。大厂对于技术的要求主要体现在:基础,原理,深入研究源码,广度,实战五个方面,也只有将原理理论结合实战才能把技术点吃透。
下面是我会看的一些资料笔记,希望能帮助大家由浅入深,由点到面的学习Java,应对大厂面试官的灵魂追问
这部分内容过多,小编只贴出部分内容展示给大家了,见谅见谅!
- Java程序员必看《Java开发核心笔记(华山版)》
- Redis学习笔记
- Java并发编程学习笔记
四部分,详细拆分并发编程——并发编程+模式篇+应用篇+原理篇
- Java程序员必看书籍《深入理解 ava虚拟机第3版》(pdf版)
- 大厂面试必问——数据结构与算法汇集笔记
其他像Spring,SpringBoot,SpringCloud,SpringCloudAlibaba,Dubbo,Zookeeper,Kafka,RocketMQ,RabbitMQ,Netty,MySQL,Docker,K8s等等我都整理好,这里就不一一展示了。
2、狂刷面试题
技术主要是体现在平时的积累实用,面试前准备两个月的时间再好好复习一遍,紧接着就可以刷面试题了,下面这些面试题都是小编精心整理的,贴给大家看看。
①大厂高频45道笔试题(智商题)
②BAT大厂面试总结(部分内容截图)
③面试总结
3、结合实际,修改简历
程序员的简历一定要多下一些功夫,尤其是对一些字眼要再三斟酌,如“精通、熟悉、了解”这三者的区别一定要区分清楚,否则就是在给自己挖坑了。当然不会包装,我可以将我的简历给你参考参考,如果还不够,那下面这些简历模板任你挑选:
以上分享,希望大家可以在金三银四跳槽季找到一份好工作,但千万也记住,技术一定是平时工作种累计或者自学(或报班跟着老师学)通过实战累计的,千万不要临时抱佛脚。
另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
的时间再好好复习一遍,紧接着就可以刷面试题了,下面这些面试题都是小编精心整理的,贴给大家看看。
①大厂高频45道笔试题(智商题)
[外链图片转存中…(img-cgLpQAgn-1712485012813)]
②BAT大厂面试总结(部分内容截图)
[外链图片转存中…(img-0xSuN6gd-1712485012813)]
[外链图片转存中…(img-HQIdthZa-1712485012813)]
③面试总结
[外链图片转存中…(img-Mj59beFs-1712485012813)]
[外链图片转存中…(img-NrSx0Xli-1712485012813)]
3、结合实际,修改简历
程序员的简历一定要多下一些功夫,尤其是对一些字眼要再三斟酌,如“精通、熟悉、了解”这三者的区别一定要区分清楚,否则就是在给自己挖坑了。当然不会包装,我可以将我的简历给你参考参考,如果还不够,那下面这些简历模板任你挑选:
[外链图片转存中…(img-r7EbBoiM-1712485012814)]
以上分享,希望大家可以在金三银四跳槽季找到一份好工作,但千万也记住,技术一定是平时工作种累计或者自学(或报班跟着老师学)通过实战累计的,千万不要临时抱佛脚。
另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!