目录
- 引出
- 数组和集合
- 建议60:性能考虑,数组是首选
- 建议61:若有必要,使用变长数组
- 建议62:警惕数组的浅拷贝
- 建议63:在明确的场景下,为集合指定初始容量
- 建议64:多种最值算法,适时选择
- 建议65:避开基本类型数组转换列表陷阱
- 建议66:asList方法产生的List对象不可更改
- 建议67:不同的列表选择不同的遍历方法
- 建议68:频繁插入和删除时使用LinkedList
- 建议69:列表相等只需关心元素数据
- 建议70:子列表只是原列表的一个视图
- 深入认识JVM
- JVM内存分配,类加载
- 创建对象的4种方法总结
- 垃圾回收GC
- JVM调优,Arthas使用
- 认识多线程
- 创建多线程方法+了解线程池
- 多线程下-1非原子性问题即解决
- 再论线程,创建、生命周期
- 总结
引出
程序人生——Java数组和集合使用建议(1)
数组和集合
建议60:性能考虑,数组是首选
- 性能要求较高的场景中使用数组替代集合)(基本类型在栈内存中操作,对象在堆内存中操作。数组中使用基本类型是效率最高的,使用集合类会伴随着自动装箱与自动拆箱动作,所以性能相对差一些
建议61:若有必要,使用变长数组
- 使用Arrays.copyOf(datas,newLen)对原数组datas进行扩容处理
建议62:警惕数组的浅拷贝
- 通过Arrays.copyOf(box1,box1.length)方法产生的数组是一个浅拷贝,这与序列化的浅拷贝完全相同:基本类型是直接拷贝值,其他都是拷贝引用地址。数组中的元素没有实现Serializable接口
建议63:在明确的场景下,为集合指定初始容量
- ArrayList集合底层使用数组存储,如果没有初始为ArrayList指定数组大小,默认存储数组大小长度为10,添加的元素达到数组临界值后,使用Arrays.copyOf方法进行1.5倍扩容处理。HashMap是按照倍数扩容的,Stack继承自Vector,所采用扩容规则的也是翻倍
建议64:多种最值算法,适时选择
- 最值计算时使用集合最简单,使用数组性能最优,利用Set集合去重,使用TreeSet集合自动排序
建议65:避开基本类型数组转换列表陷阱
- 原始类型数组不能作为asList的输入参数,否则会引起程序逻辑混乱)(基本类型是不能泛化的,在java中数组是一个对象,它是可以泛化的。使用Arrays.asList(data)方法传入一个基本类型数组时,会将整个基本类型数组作为一个数组对象存入,所以存入的只会是一个对象。JVM不可能输出Array类型,因为Array是属于java.lang.reflect包的,它是通过反射访问数组元素的工具类。在Java中任何一个数组的类都是“[I”,因为Java并没有定义数组这个类,它是编译器编译的时候生成的,是一个特殊的类
建议66:asList方法产生的List对象不可更改
- 使用add方法向asList方法生成的集合中添加元素时,会抛UnsupportedOperationException异常。原因:asList生成的ArrayList集合并不是java.util.ArrayList集合,而是Arrays工具类的一个内置类,我们经常使用的List.add和List.remove方法它都没有实现,也就是说asList返回的是一个长度不可变的列表。此处的列表只是数组的一个外壳,不再保持列表动态变长的特性
建议67:不同的列表选择不同的遍历方法
- ArrayList数组实现了RandomAccess接口(随机存取接口),ArrayList是一个可以随机存取的列表。集合底层如果是基于数组实现的,实现了RandomAccess接口的集合,使用下标进行遍历访问性能会更高;底层使用双向链表实现的集合,使用foreach的迭代器遍历性能会更高
建议68:频繁插入和删除时使用LinkedList
- ArrayList集合,每次插入或者删除一个元素,其后的所有元素就会向后或者向前移动一位,性能很低。LinkedList集合插入时不需要移动其他元素,性能高;修改元素,LinkedList集合比ArrayList集合要慢很多;添加元素,LinkedList与ArrayList集合性能差不多,LinkedList添加一个ListNode,而ArrayList则在数组后面添加一个Entry
建议69:列表相等只需关心元素数据
- 判断集合是否相等时只须关注元素是否相等即可(ArrayList与Vector都是List,都实现了List接口,也都继承了AbstractList抽象类,其equals方法是在AbstractList中定义的。所以只要求两个集合类实现了List接口就成,不关心List的具体实现类,只要所有的元素相等,并且长度也相等就表明两个List是相等的,与具体的容量类型无关
建议70:子列表只是原列表的一个视图
- 使用==判断相等时,需要满足两个对象地址相等,而使用equals判断两个对象是否相等时,只需要关注表面值是否相等。subList方法是由AbstractList实现的,它会根据是不是可以随机存取来提供不同的SubList实现方式,RandomAccessSubList是SubList子类,SubList类中subList方法的实现原理:它返回的SubList类是AbstractList的子类,其所有的方法如get、set、add、remove等都是在原始列表上的操作,它自身并没有生成一个数组或是链表,也就是子列表只是原列表的一个视图,所有的修改动作都反映在了原列表上)。
深入认识JVM
JVM内存分配,类加载
Java进阶(1)——JVM的内存分配 & 反射Class类的类对象 & 创建对象的几种方式 & 类加载(何时进入内存JVM)& 注解 & 反射+注解的案例
创建对象的4种方法总结
Java进阶(4)——结合类加载JVM的过程理解创建对象的几种方式:new,反射Class,克隆clone(拷贝),序列化反序列化
垃圾回收GC
Java进阶(垃圾回收GC)——理论篇:JVM内存模型 & 垃圾回收定位清除算法 & JVM中的垃圾回收器
简介:本篇博客介绍JVM的内存模型,对比了1.7和1.8的内存模型的变化;介绍了垃圾回收的语言发展;阐述了定位垃圾的方法,引用计数法和可达性分析发以及垃圾清除算法;然后介绍了Java中的垃圾回收器,由串行、到并行再到并发,最后到G1的演变;最后给出了垃圾回收器的对比和使用指引。
JVM调优,Arthas使用
- Java进阶(JVM调优)——阿里云的Arthas的使用 & 安装和使用 & 死锁查找案例,重新加载案例,慢调用分析
- Java进阶(JVM调优)——JVM调优参数 & JDK自带工具使用 & 内存溢出和死锁问题案例 & GC垃圾回收
认识多线程
创建多线程方法+了解线程池
Java进阶(5)——创建多线程的方法extends Thread和implements Runnable的对比 & 线程池及常用的线程池
多线程下-1非原子性问题即解决
Java进阶(6)——抢购问题中的数据不安全(非原子性问题)& Java中的synchronize和ReentrantLock锁使用 & 死锁及其产生的条件
再论线程,创建、生命周期
Java进阶(再论线程)——线程的4种创建方式 & 线程的生命周期 & 线程的3大特性 & 集合中的线程安全问题
主要内容:
1.线程创建的方式,继承Thread类,实现Runable接口,实现Callable接口,采用线程池;
2.线程生命周期: join():运行结束再下一个, yield():暂时让出cpu的使用权,deamon():守护线程,最后结束,sleep():如果有锁,不会让出;
3.线程3大特性,原子性,可见性,有序性;
4.list集合中线程安全问题,hash算法问题;
总结
程序人生——Java数组和集合使用建议(1)