nodejs做网站容易被攻击吗,东莞找工作在什么平台找合适,网页制作代码html制作一个网页,北京飞雨网站建设公司写在开头
开年第一篇#xff0c;先祝各位新的一年身体健康#xff0c;学业有成#xff0c;事业有成哈#xff0c;春节期间就是咔咔乱吃#xff0c;咔咔乱玩#xff0c;把学习都抛一边子去了#xff0c;已经9天没有学习了#xff0c;深深的懊悔#xff0c;从今天开始先祝各位新的一年身体健康学业有成事业有成哈春节期间就是咔咔乱吃咔咔乱玩把学习都抛一边子去了已经9天没有学习了深深的懊悔从今天开始2024年的学习正式开启一起给我猛冲 书接上回我们开启了Java集合部分的学习今天我们就来看一下List其中它的核心有两个一个ArrayList一个LinkedList而ArrayList的使用频率在集合中至少排第二可以和HashMap掰掰手腕子 盘点Java集合容器概览Collection和Map在开发中谁用的最多
问一ArrayList和Array的区别
Array(数组)是一种引用类型主要作用是用来存储数据即可存储基本数据类型也可存储对象但在定义一个数组时需要注意必须指定数组的数据类型及数组长度即数组中存放的元素个数固定并且类型相同。故我们也可以将Array称作静态数组。
【代码示例1】
//数组的几种声明方式
int[] array new int[3];
int array [] new int[3];
int[] array {1, 2, 3};
int[] array new int[]{1, 2, 3};而ArrayList的底层是通过动态数组实现长度动态可变会自动扩容。不使用泛型的时候可以添加不同类型元素。
【代码示例2】
List list new ArrayList(4);
list.add(1);
list.add(1);
list.add(new Double(1.1));
list.add(Happy New Year);
for (Object o : list) {System.out.println(o);
}区别总结
1、ArrayList会根据实际存储的元素动态地扩容或缩容而 Array 被创建之后就不能改变它的长度了。
2、ArrayList 允许你使用泛型来确保类型安全Array 则不可以。
3、ArrayList 中只能存储对象。对于基本类型数据需要使用其对应的包装类如 Integer、Double 等。Array 可以直接存储基本类型数据也可以存储对象。
4、ArrayList 支持插入、删除、遍历等常见操作并且提供了丰富的 API 操作方法比如 add()、remove()等。Array 只是一个固定长度的数组只能按照下标访问其中的元素不具备动态添加、删除元素的能力。
5、ArrayList创建时不需要指定大小而Array创建时必须指定大小。问二ArrayList和Vector的区别
二者都是List的实现类底层都通过object[]数组实现但Vector是早起JDK支持的集合类目前几乎全部ArrayList替代二者有着相似的增删改查功能但不同的是Vector的方法都是同步的可以保证线程安全而ArrayList则不是因此ArrayList相较于Vector拥有良好的性能两者的扩容也存在着不同默认初始化容量都是10Vector 扩容默认会翻倍可指定扩容的大小ArrayList只增加 50%
问三ArrayList和LinkedList的区别
作为List的另外一个子类LinkedList的出镜率虽然没有ArrayList高但总有一些场景会用到我们还是要学一下的哈。 LinkedList的底层是用过双向链表实现我们简单的感受一下它的使用后面会针对LinkedList专门总结一篇博客。
【代码示例3】 // 创建LinkedList集合LinkedList link new LinkedList();// 1、添加元素link.add(happy);link.add(new);link.offer(year); // 向集合尾部追加元素link.push(javabuild); // 向集合头部添加元素System.out.println(link); // 输出集合中的元素// 2、获取元素Object object link.peek(); //获取集合第一个元素System.out.println(object); // 输出集合中的元素// 3、删除元素link.removeFirst(); // 删除集合第一个元素link.pollLast(); // 删除集合最后一个元素System.out.println(link);【输出】
[javabuild, happy, new, year]
javabuild
[happy, new]区别总结
ArrayList 和 LinkedList 都是不同步的也就是不保证线程安全ArrayList 底层使用的是 Object 数组LinkedList 底层使用的是双向链表数据结构LinkedList 不支持高效的随机元素访问而 ArrayList实现了 RandomAccess 接口 支持。ArrayList存在扩容问题LinkedList不存在直接放在集合尾部修改指针即可
问四知道ArrayList的扩容机制吗
要想充分的了解ArrayList的扩容必须静心阅读其底层源码JDK1.8源码如下
public class ArrayListE extends AbstractListEimplements ListE, RandomAccess, Cloneable, java.io.Serializable {private static final long serialVersionUID 8683452581122892189L;/*** 默认初始容量大小*/private static final int DEFAULT_CAPACITY 10;/*** 空数组用于空实例。*/private static final Object[] EMPTY_ELEMENTDATA {};//用于默认大小空实例的共享空数组实例。//我们把它从EMPTY_ELEMENTDATA数组中区分出来以知道在添加第一个元素时容量需要增加多少。private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA {};/*** 保存ArrayList数据的数组*/transient Object[] elementData; // non-private to simplify nested class access/*** ArrayList 所包含的元素个数*/private int size;/*** 带初始容量参数的构造函数用户可以在创建ArrayList对象时自己指定集合的初始大小*/public ArrayList(int initialCapacity) {if (initialCapacity 0) {//如果传入的参数大于0创建initialCapacity大小的数组this.elementData new Object[initialCapacity];} else if (initialCapacity 0) {//如果传入的参数等于0创建空数组this.elementData EMPTY_ELEMENTDATA;} else {//其他情况抛出异常throw new IllegalArgumentException(Illegal Capacity: initialCapacity);}}/*** 默认无参构造函数* DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为0.初始化为10也就是说初始其实是空数组 当添加第一个元素的时候数组容量才变成10*/public ArrayList() {this.elementData DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}/*** 构造一个包含指定集合的元素的列表按照它们由集合的迭代器返回的顺序。*/public ArrayList(Collection? extends E c) {//将指定集合转换为数组elementData c.toArray();//如果elementData数组的长度不为0if ((size elementData.length) ! 0) {// 如果elementData不是Object类型数据c.toArray可能返回的不是Object类型的数组所以加上下面的语句用于判断if (elementData.getClass() ! Object[].class)//将原来不是Object类型的elementData数组的内容赋值给新的Object类型的elementData数组elementData Arrays.copyOf(elementData, size, Object[].class);} else {// 其他情况用空数组代替this.elementData EMPTY_ELEMENTDATA;}}/*** 修改这个ArrayList实例的容量是列表的当前大小。 应用程序可以使用此操作来最小化ArrayList实例的存储。*/public void trimToSize() {modCount;if (size elementData.length) {elementData (size 0)? EMPTY_ELEMENTDATA: Arrays.copyOf(elementData, size);}}
//下面是ArrayList的扩容机制
//ArrayList的扩容机制提高了性能如果每次只扩充一个
//那么频繁的插入会导致频繁的拷贝降低性能而ArrayList的扩容机制避免了这种情况。/*** 如有必要增加此ArrayList实例的容量以确保它至少能容纳元素的数量** param minCapacity 所需的最小容量*/public void ensureCapacity(int minCapacity) {//如果是trueminExpand的值为0如果是false,minExpand的值为10int minExpand (elementData ! DEFAULTCAPACITY_EMPTY_ELEMENTDATA)// any size if not default element table? 0// larger than default for default empty table. Its already// supposed to be at default size.: DEFAULT_CAPACITY;//如果最小容量大于已有的最大容量if (minCapacity minExpand) {ensureExplicitCapacity(minCapacity);}}// 根据给定的最小容量和当前数组元素来计算所需容量。private static int calculateCapacity(Object[] elementData, int minCapacity) {// 如果当前数组元素为空数组初始情况返回默认容量和最小容量中的较大值作为所需容量if (elementData DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}// 否则直接返回最小容量return minCapacity;}// 确保内部容量达到指定的最小容量。private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}//判断是否需要扩容private void ensureExplicitCapacity(int minCapacity) {modCount;// overflow-conscious codeif (minCapacity - elementData.length 0)//调用grow方法进行扩容调用此方法代表已经开始扩容了grow(minCapacity);}/*** 要分配的最大数组大小*/private static final int MAX_ARRAY_SIZE Integer.MAX_VALUE - 8;/*** ArrayList扩容的核心方法。*/private void grow(int minCapacity) {// oldCapacity为旧容量newCapacity为新容量int oldCapacity elementData.length;//将oldCapacity 右移一位其效果相当于oldCapacity /2//我们知道位运算的速度远远快于整除运算整句运算式的结果就是将新容量更新为旧容量的1.5倍int newCapacity oldCapacity (oldCapacity 1);//然后检查新容量是否大于最小需要容量若还是小于最小需要容量那么就把最小需要容量当作数组的新容量if (newCapacity - minCapacity 0)newCapacity minCapacity;//再检查新容量是否超出了ArrayList所定义的最大容量//若超出了则调用hugeCapacity()来比较minCapacity和 MAX_ARRAY_SIZE//如果minCapacity大于MAX_ARRAY_SIZE则新容量则为Integer.MAX_VALUE否则新容量大小则为 MAX_ARRAY_SIZE。if (newCapacity - MAX_ARRAY_SIZE 0)newCapacity hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData Arrays.copyOf(elementData, newCapacity);}//比较minCapacity和 MAX_ARRAY_SIZEprivate static int hugeCapacity(int minCapacity) {if (minCapacity 0) // overflowthrow new OutOfMemoryError();return (minCapacity MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;}/*** 返回此列表中的元素数。*/public int size() {return size;}/*** 如果此列表不包含元素则返回 true 。*/public boolean isEmpty() {//注意和的区别return size 0;}/*** 如果此列表包含指定的元素则返回true 。*/public boolean contains(Object o) {//indexOf()方法返回此列表中指定元素的首次出现的索引如果此列表不包含此元素则为-1return indexOf(o) 0;}/*** 返回此列表中指定元素的首次出现的索引如果此列表不包含此元素则为-1*/public int indexOf(Object o) {if (o null) {for (int i 0; i size; i)if (elementData[i] null)return i;} else {for (int i 0; i size; i)//equals()方法比较if (o.equals(elementData[i]))return i;}return -1;}/*** 返回此列表中指定元素的最后一次出现的索引如果此列表不包含元素则返回-1。.*/public int lastIndexOf(Object o) {if (o null) {for (int i size - 1; i 0; i--)if (elementData[i] null)return i;} else {for (int i size - 1; i 0; i--)if (o.equals(elementData[i]))return i;}return -1;}/*** 返回此ArrayList实例的浅拷贝。 元素本身不被复制。*/public Object clone() {try {ArrayList? v (ArrayList?) super.clone();//Arrays.copyOf功能是实现数组的复制返回复制后的数组。参数是被复制的数组和复制的长度v.elementData Arrays.copyOf(elementData, size);v.modCount 0;return v;} catch (CloneNotSupportedException e) {// 这不应该发生因为我们是可以克隆的throw new InternalError(e);}}/*** 以正确的顺序从第一个到最后一个元素返回一个包含此列表中所有元素的数组。* 返回的数组将是“安全的”因为该列表不保留对它的引用。 换句话说这个方法必须分配一个新的数组。* 因此调用者可以自由地修改返回的数组。 此方法充当基于阵列和基于集合的API之间的桥梁。*/public Object[] toArray() {return Arrays.copyOf(elementData, size);}/*** 以正确的顺序返回一个包含此列表中所有元素的数组从第一个到最后一个元素;* 返回的数组的运行时类型是指定数组的运行时类型。 如果列表适合指定的数组则返回其中。* 否则将为指定数组的运行时类型和此列表的大小分配一个新数组。* 如果列表适用于指定的数组其余空间即数组的列表数量多于此元素则紧跟在集合结束后的数组中的元素设置为null 。* 这仅在调用者知道列表不包含任何空元素的情况下才能确定列表的长度。*/SuppressWarnings(unchecked)public T T[] toArray(T[] a) {if (a.length size)// 新建一个运行时类型的数组但是ArrayList数组的内容return (T[]) Arrays.copyOf(elementData, size, a.getClass());//调用System提供的arraycopy()方法实现数组之间的复制System.arraycopy(elementData, 0, a, 0, size);if (a.length size)a[size] null;return a;}// Positional Access OperationsSuppressWarnings(unchecked)E elementData(int index) {return (E) elementData[index];}/*** 返回此列表中指定位置的元素。*/public E get(int index) {rangeCheck(index);return elementData(index);}/*** 用指定的元素替换此列表中指定位置的元素。*/public E set(int index, E element) {//对index进行界限检查rangeCheck(index);E oldValue elementData(index);elementData[index] element;//返回原来在这个位置的元素return oldValue;}/*** 将指定的元素追加到此列表的末尾。*/public boolean add(E e) {ensureCapacityInternal(size 1); // Increments modCount!!//这里看到ArrayList添加元素的实质就相当于为数组赋值elementData[size] e;return true;}/*** 在此列表中的指定位置插入指定的元素。* 先调用 rangeCheckForAdd 对index进行界限检查然后调用 ensureCapacityInternal 方法保证capacity足够大* 再将从index开始之后的所有成员后移一个位置将element插入index位置最后size加1。*/public void add(int index, E element) {rangeCheckForAdd(index);ensureCapacityInternal(size 1); // Increments modCount!!//arraycopy()这个实现数组之间复制的方法一定要看一下下面就用到了arraycopy()方法实现数组自己复制自己System.arraycopy(elementData, index, elementData, index 1,size - index);elementData[index] element;size;}/*** 删除该列表中指定位置的元素。 将任何后续元素移动到左侧从其索引中减去一个元素。*/public E remove(int index) {rangeCheck(index);modCount;E oldValue elementData(index);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//从列表中删除的元素return oldValue;}/*** 从列表中删除指定元素的第一个出现如果存在。 如果列表不包含该元素则它不会更改。* 返回true如果此列表包含指定的元素*/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;}/** 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}/*** 从列表中删除所有元素。*/public void clear() {modCount;// 把数组中所有的元素的值设为nullfor (int i 0; i size; i)elementData[i] null;size 0;}/*** 按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。*/public boolean addAll(Collection? extends E c) {Object[] a c.toArray();int numNew a.length;ensureCapacityInternal(size numNew); // Increments modCountSystem.arraycopy(a, 0, elementData, size, numNew);size numNew;return numNew ! 0;}/*** 将指定集合中的所有元素插入到此列表中从指定的位置开始。*/public boolean addAll(int index, Collection? extends E c) {rangeCheckForAdd(index);Object[] a c.toArray();int numNew a.length;ensureCapacityInternal(size numNew); // Increments modCountint numMoved size - index;if (numMoved 0)System.arraycopy(elementData, index, elementData, index numNew,numMoved);System.arraycopy(a, 0, elementData, index, numNew);size numNew;return numNew ! 0;}/*** 从此列表中删除所有索引为fromIndex 含和toIndex之间的元素。* 将任何后续元素移动到左侧减少其索引。*/protected void removeRange(int fromIndex, int toIndex) {modCount;int numMoved size - toIndex;System.arraycopy(elementData, toIndex, elementData, fromIndex,numMoved);// clear to let GC do its workint newSize size - (toIndex - fromIndex);for (int i newSize; i size; i) {elementData[i] null;}size newSize;}/*** 检查给定的索引是否在范围内。*/private void rangeCheck(int index) {if (index size)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}/*** add和addAll使用的rangeCheck的一个版本*/private void rangeCheckForAdd(int index) {if (index size || index 0)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}/*** 返回IndexOutOfBoundsException细节信息*/private String outOfBoundsMsg(int index) {return Index: index , Size: size;}/*** 从此列表中删除指定集合中包含的所有元素。*/public boolean removeAll(Collection? c) {Objects.requireNonNull(c);//如果此列表被修改则返回truereturn batchRemove(c, false);}/*** 仅保留此列表中包含在指定集合中的元素。* 换句话说从此列表中删除其中不包含在指定集合中的所有元素。*/public boolean retainAll(Collection? c) {Objects.requireNonNull(c);return batchRemove(c, true);}/*** 从列表中的指定位置开始返回列表中的元素按正确顺序的列表迭代器。* 指定的索引表示初始调用将返回的第一个元素为next 。 初始调用previous将返回指定索引减1的元素。* 返回的列表迭代器是fail-fast 。*/public ListIteratorE listIterator(int index) {if (index 0 || index size)throw new IndexOutOfBoundsException(Index: index);return new ListItr(index);}/*** 返回列表中的列表迭代器按适当的顺序。* 返回的列表迭代器是fail-fast 。*/public ListIteratorE listIterator() {return new ListItr(0);}/*** 以正确的顺序返回该列表中的元素的迭代器。* 返回的迭代器是fail-fast 。*/public IteratorE iterator() {return new Itr();}通过阅读源码和其中注释我们不难得出这样的结论ArrayList的无参构造默认初始化长度为10在添加元素大于初始容量后会触发扩容而数组的扩容是将原数组中的元素拷贝到一个新数组中将数组容量增加为原数组1.5倍。
问五ArrayList增删改查的时间复杂度
查询时间复杂度 O(1)因为 ArrayList 内部使用数组来存储元素所以可以直接根据索引来访问元素。增加时间复杂度添加一个元素调用 add() 方法时的时间复杂度最好情况为 O(1)最坏情况为 O(n)。删除时间复杂度删除一个元素调用 remove(Object) 方法时的时间复杂度最好情况 O(1)最坏情况 O(n)。修改时间复杂度修改一个元素调用 set()方法时与查询操作类似可以直接根据索引来访问元素时间复杂度为 O(1)。
注最好和最快情况分别是在列别尾部操作和头部或中间操作的差距。
问六Vector、ArrayList、LinkedList 的存储性能和特性
1、ArrayList 和 Vector 都是使用数组存储数据
2、ArrayList 允许直接按序号索引元素
3、ArrayList 插入元素涉及数组扩容、元素移动等内存操作
4、ArrayList 根据下标找元素快存在扩容的情况下插入慢
5、Vector 对元素的操作使用了 synchronized 方法性能比 ArrayList 差
6、Vector 属于遗留容器早期的 JDK 中使用的容器
7、LinkedList 使用双向链表存储元素
8、LinkedList 按序号查找元素需要进行前向或后向遍历所以按下标查找元素效率较低
9、LinkedList 非线程安全
10、LinkedList 使用的链式存储方式与数组的连续存储方式相比对内存的利用率更高
11、LinkedList 插入数据时只需要移动指针即可所以插入速度较快结尾彩蛋
如果本篇博客对您有一定的帮助大家记得留言点赞收藏呀。原创不易转载请联系Build哥