集合初始化通常进行分配容量,设置特定参数等相关工作,推荐在任何情况下,都需要显式地设定集合容量的初始大小。
ArrayList 使用无参构造时,默认大小为 10 ,也就是说在第一次add的时候,分配为10的容量,后续的每次扩容都会调用Array.copyOf 方法,创建新数组现复制。可以想像,假如需要将1000个元素放置在ArrayList中采用默认构造器方法,则需要被动扩容13次才可以完成存储。反之,如果在初始化进便指定了容量,newArrayList(1000) ,那么初始化ArrayList 对像的时候就直接分配1000个存储空间,从而避免被动扩容和数组复制的额外开销。
HashMap 使用无参构造时,默认大小为16,如果要放置1000个元素,需要被动扩容7次才可以完成存储。扩容时需要重建hash表,非常影响性能。HashMap容量并不会在new的时候分配,而是在第一次put的时候完成创建。
泛型
List List<Object> List<?> List<? extends T> List<? super T>
List: 完全没有 类型的限制和赋值的限定
List<Object> 是一个泛型,只能赋值Object泛型
List<Integer> integerList = new ArrayList<>();
List<Object> objectList = integerList; //编译不通过
List<?> 是一个泛型,可以接受任何类型的集合赋值(不是添加元素),赋值之后就不能随便住里添加元素了。它一般作为参数来接收外部的集合,或者返回一个不知道具体类型的集合
List<?> list = new ArrayList<Integer>();
list.add(1); //编译不能通过
List<? extend T> 可以赋值给任何T及T子类的集合,上界为T 。取出来的类型带有泛型限制,向上强制转型为T,即只能返回T和T的父类。 除了null外,任何元素都不得添加进集合内(无法使用add 方法) ,add 受限
List<? super T> 可以赋值给任何T及T父类集合,下界为T。可以添加T及T的子类元素,但返回时的元素类型只能是Object,泛型丢失。 get功能受限
总结:如果集合属于 get first 应采用<? extend T> ,add first 应采用<? super T>
其他
1.Arrays.asList() 转成集合时,是不能进行add/remove/clear 的,会抛出unsuppotedOperationExecption异常
2.list.toArray() 建议不要使用无参调用,将泛型丢失 。
3.list.toArray(array) 参数中数组的大小要与集合类型一样,如果数组长度小于集合元素个数,将复制失败全部输出Null。如果数组的大小与与元素的大小不一样还会降低性能
4.对象如果覆写了equal 也要复写hashCode
5.使用ArrayList.subList 方法生成子列表,如果主列表集合的个数增加或删除,会导致子列表的遍历,增加,删除失败,抛出ConcurrrentModificationException。并且子列表是无没有 实现序列化接口无法在网络中传输。
摘自- 《码出高效》