美文网首页
集合增长、删除、泛型那些事儿-List

集合增长、删除、泛型那些事儿-List

作者: Bardon_X | 来源:发表于2019-03-07 16:27 被阅读0次

引言:

对于这段代码,我们肯定是觉得有问题的,那么它的问题在那儿呢?如果换成:

又会有什么问题?

这段代码,java是如何操作的?初始化时,初始容量是多少? 本章内容就来聊聊这些事儿!

1、初始化方法:

第一种,使用int类型入参,构造一个capacity大小的数组。

第二种,使用无参的构造方法,设置了一个空的数组

private static final Object[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

同时初始化容量为10 private static final int DEFAULT_CAPACITY =10;

第三种,则是通过传入一个类型是当前类型派生类的集合。

这里先引申讲一下泛型。

1.1、泛型

1.1.1、这里先摆出几个事实:

①虚拟机中没有泛型,只有普通的类和方法。

(泛型擦除:无论何时定义一个泛型类型,都自动提供一个相应的原始类型。即擦除类型变量,替换为限定类型

如 Pair<T> 会替换为Pair<Object> ,Pair<T extends Comparable>会替换成Pair<Comparable>

特例Pair<T extends Serializable & Comparable> 会替换成Pair<Serializable>,为了提高效率,应该将标签接口(无方法接口)放在列表末尾)

②所有的类型参数都用它们的限定类型替换。

(当程序调用泛型方法,如果擦除返回类型,编译器自动插入强制类型转换)

③桥方法被合成来保持多态。

(泛型擦除与多态发生矛盾,即会产生两个方法:Object get();  Basic get();<直接这样编码,编译器会报错>但是在虚拟机中,用参数类型和返回类型确定一个方法,编译器可能产生两个返回类型不同的方法字节码,虚拟机能够正确处理。

一个方法覆盖另一个方法时,可以指定一个更严格的返回类型。合成的桥方法调用了新定义的方法,即

public void setSecond(Object second){setSecond((Date)second)})

④为保持类型安全性,必要时插入强制类型转换。

下面以一张图讲述区别

1.1.2、约束和局限性

①不能用基本数据类型实例化类型参数,例如List<int>。

②运行时类型查询只适用于原始类型。

③不能创建参数化类型数组,例如 List<Integer>[]。

④Varages警告 例如:@SafeVerargs  <T> void addAll(Collection<T> col, T... ts) 仅限于最常见事例。

⑤不能实例化类型变量  ClassCastException 。

⑥不能构造泛型数组

⑦泛型类的静态上下文中类型变量无效

⑧不能捕获或抛出泛型类的实例

2、集合增长

2.1、集合增长首先看add方法。

所有的add方法都会调用一个private void ensureCapacityInternal(int minCapacity) 方法,minCapacity 是当前size+addnum。

如代码所示:如elementData是一个空数组Object[],比较默认容量(10)和minCapacity大小,此分支只会在第一次添加元素时进入。再modCount++(这是个隐含点),若minCapacity大于数组容量,则增长。

注意:int类型构造方法是this.elementData =new Object[initialCapacity]; 操作,直接设置数组大小。设置合适的容量,可避免频繁扩容。

如代码所示:获取数组长度(默认10),第一次扩容约1.5倍,如果不够,直接扩容到实际大小,如果还是不够。

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE -8;

@Native public static final int MAX_VALUE =0x7fffffff;

return (minCapacity >MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;

只能扩到最大值-8这个区间,约21亿

3、移除元素

分两种情况,for循环移除和迭代器移除(即增强for循环)

3.1、for(int i = 0;i<arrayList.size(); i++) {arrayList.remove(i); },简称锯齿状,每次remove,数组都会重新构造。例如,删除index值为0的,删除后,index为1的值到了第一位,index值自增为2只想数据3。正确清空可while(arrayList.size()>0){arrayList.remove(0);} 或者arrayList.clear();

3.2、for (Integer a: arrayList) {arrayList.remove(a);} 与 for (int a: arrayList) {arrayList.remove(a);} 其实并没有区别。前一篇文章集合遍历有提到,使用增强for循环编译器会编译成迭代器方式。

它的方法都会调用一下checkForComodification(),

而所有的增、删操作都会自增modCount,导致抛出传说中的ConcurrentModificationException异常。而迭代器的remove操作会及时更新expectedModCount值,所以可迭代删除,即Iterator<Integer> iterable = arrayList.iterator();while(iterable.hasNext()) {iterable.next();iterable.remove();}。

总结:这篇文章主要总结了一下集合操作这块内容,顺带捋了一下泛型相关内容,很遗憾自己在整理这篇文章之前,就在面试中犯过错。

参考:

1、Java核心技术 卷一

2、Java API Docs

相关文章

网友评论

      本文标题:集合增长、删除、泛型那些事儿-List

      本文链接:https://www.haomeiwen.com/subject/iqhcpqtx.html