前言
在看狂神频道的时候偶然发现下图,感触颇深。特别在当今【程序 = 业务 + 框架】思想盛行的开发者中,夯实基础基础显得格外重要,因此开此专栏总结记录。
Java语言基础
这个题目能够考察到数据结构Java 基础实现以及对并发问题的处理思路的掌握程度
- HashMap与 CurrentHashMap
- Java 的不同版本新技术特性
- map 的实现
集合类:
-
常用集合类实现与 Java 并发工具包juc是常见的考点(多线程章节详解)
-
Java 的集合类部分需要重点了解类的实现,例如HashMap 、Treemap是如何实现的呢
知识点脑图:图源:三太子敖丙
HashMap:
-
先来看HashMap的实现
-
简单来说:Java的HashMap就是数组加链表,实现的数组中的每一项是一个链表,通过计算存入对象的hashcode的来计算出对象在数组中要存入的位置,用链表来解决散列冲突,列表中的节点存储的是键值对。
-
除了实现的方式外,我们还需要知道填充因子的作用与map 扩容时的rehash机制,需要知道hashmap容量都是二的幂次方:是因为可以通过按位与操作来计算余数,比求模要更快
-
-
版本区别:
参考:HashMap 1.7和1.8的区别 --答到面试官怀疑人生
吐槽下现在博客标题都这么卷了吗,越来越浮夸,不过好在内容不错
-
扩容机制:
-
当HashMap决定扩容时,会调用HashMap类中的resize(int newCapacity) 方法,参数是新的table长度。在JDK1.7和JDK1.8的扩容机制有很大不同。
-
1.7:
- 使用的是头插法,也就是说,新table中链表的顺序和旧列表中是相反的,在HashMap线程不安全的情况下,这种头插法可能会导致环状节点。
-
1.8:
- 使用的是尾插法
- 为什么要从头插法改成尾插法?
- 因为头插法会造成死链:hashmap扩容时死循环问题
- JDK7用头插是考虑到了一个所谓的热点数据的点(新插入的数据可能会更早用到),但这其实是个伪命题,因为JDK7中rehash的时候,旧链表迁移新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置(就是因为头插) 所以最后的结果 还是打乱了插入的顺序 所以总的来看支撑JDK7使用头插的这点原因也不足以支撑下去了 所以就干脆换成尾插 一举多得
-
-
非线程安全:
-
线上结论:HashMap是非线程安全的,在多线程put 的情况下,有可能在容量超过填充因子时进行rehash,因为HashMap 为了避免尾部遍历,在链表的插入时使用的是头插法,多线程场景下可能会产生死循环
-
具体原因:
-
-
为什么必须重写equals和Hashcode?
-
先上结论:当该Object需要在Hashmap当成Key的时候必须要重写equals和Hashcode方法(当键值为对象类型的时候就需要重写hashCode和equals方法。)
-
实验如下:(案例1)
public class Person { public int no; public String name; public Person(int no, String name) { this.no = no; this.name = name; } public static void main(String[] args) { Person p1 = new Person(1,"11"); Person p2 = new Person(1,"11"); HashMap<Person, Integer> map = new HashMap<>(); map.put(p1,1); map.put(p2,2); System.out.println(map.get(new Person(1,"11"))); } } //此时的打印结果为null
-
但map中的key都一样,为什么取不到相应的value呢?
- 原因:由于在hashMap中在put时,散列函数根据它的哈希值找到对应的位置,如果该位置有原素,首先会使用hashCode方法判断,如果没有重写hashCode方法,那么即使俩个对象属性相同hashCode方法也会认为他们是不同的元素,又因为Set是不可以有重复的,所以这会产生矛盾,那么就需要重写hashCode方法。
-
这时候又要上经典结论了:当两个对象:
- equals为true,他们hashcode一定相等
- equals!=true,他们的equals有可能相等
- hashcode相等,不一定equals
- hashcode不相等,一定不equals
-
此时上案例2:
//在案例1内重写equals和hashcode方法 @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Person person = (Person) o; if (no != person.no) { return false; } return name != null ? name.equals(person.name) : person.name == null; } @Override public int hashCode() { int result = no; result = 31 * result + (name != null ? name.hashCode() : 0); return result; } //运行结果: //2 //证明通过对象key获取到了对应数据
-
ConcurrentHashMap:
采用分段锁的思想来降低并发场景下的锁定发生频率:
- 在JDK 1.7和1.8中的实现差异非常大:
- 1.7
- 中使用的segment进行分段加锁,降低并发锁定程度
- 1.8
- 使用CAS自选锁,这是一种乐观锁模式来提高性能,但是在并发度较高的场景下性能会比较一般,
- concurrentHashMap引入了红黑树,用来解决哈希冲突时列表的顺序查找问题,红黑树的使用条件与链表的长度和map 的总容量有关
- 1.7
- 默认是链表大于8且容量大于64时,转为红黑树方式这部分内容建议详细阅读源码进行学习
ArrayList
- 数据结构:底层是用数组实现
- 特性:有下标,因此查询速度快
LinkedList
- 数据结构:底层用双向链表是实现
- 特点:适合删改操作
动态代理和反射
- 动态代理与反射是Java语言的特色,需要掌握动态代理与反射的使用场景
- 例如在ORM框架中会大量使用代理类,而PRC调用时会使用反射机制,调用时间类的方法
- 学习博客:厚积薄发打卡Day36 :[itcast] GoF23通俗易懂的设计模式之 <代理模式>
数据类型:
- Java基础数据类型
- 每种数据类型占用多大的内存空间,数据类型的自动转换与强制转换,基础数据类型与封装数据类型的自动装箱与拆箱等等
Java对象引用
- Java 对对象的引用分为四种:
- 强引用
- 弱引用
- 软引用
- 虚引用
- 这些引用在GC时的处理策略不同:
- 强引用不会被GC回收
- 软引用在内存空间不足时会被GC回收
- 弱引用在每次GC时都会被回收
- 虚引用必须和引用队列联合使用,主要用于跟踪一个对象被垃圾回收的过程
Java异常处理机制
- Java 的异常处理机制就是try catch finally 机制需要知道异常时
- 在try catch 中的处理流程需要了解error 和exception 的区别
Java注解
Java 的不同版本新技术特性
- Java 近些年一改以往的版本发布风格,发布频率提高了很多,目前大部分公司的生产环境
使用的还是1.8版本一少部分公司升级到1.9 或者1.10 - Java 的1.8版本是个长期知识版本也是一个长期支持版本,所以这两个版本是我们要重点关注的版本
- 在1.8版本中:
- Java 增加了lambda表达式的支持,使Java 代码的编写,可以更简洁,也更方便支持并行计算
- 1.8 提供了很多stream 流失处理api还支持了方法引用的能力可以进一步简化lambda表达式的写法
- 在1.8中接口可以提供默认方法了,这样可以简化掉一些简单的抽象类
- 最后在1.8 中对方法区进行了调整:
- 使用meta space 替换掉了prom generation 的永久带,meta space 与prom generation 之间最大的区别在于mat space 并不在虚拟机中,而是使用本地内存替换的目的,一方面是可以提升对原数据的处理,提升gc 效率;另一方面方便后续hot spot 与jerusalem 合并
- 在1.9和1.10中:
- 主要的特性是增加了模块系统,将G1做作为了默认的垃圾回收器,支持局部的Bean量推断等功能,这些功能都已经包含在1.11中
- 1.11 版本是Java 最新的长期知识版本,也会是将来一段时间的主要版本:
- 1.11版本提供的最激动人心的功能就要数ZGC这个新的垃圾回收器了,ZGC为大内存吨设计,有着非常强悍的性能,能够实现十毫秒以下的GC停顿,关于ZGC会在下一课中进行进一步的介绍
- 1.11版本对字符串处理的API 进行了增强,提供了字符复制等功能
- 1.11 版本还内置了http client
考察点和加分项
总结本课的考察点:
- 第一个考察点就是对基本概念和基本原理的考察要求这两项的理解必须是正确的清晰的
- 例如网络协议的四七层模型的概念
- TCP协议流量控制的实现原理等
- 第二个考察点是常用工具模型
- 它的实现方式和使用姿势
- 例如HashMap在jdk1.8中的实现方式是怎样的
- 单例模式有哪几种实现方式
- 什么场景下该使用静态方法实现什么场景下该使用双重检查实现
- 它的实现方式和使用姿势
- 第三个考察点是经常使用到的一些知识点
- 例如你常用的linux命令有哪些都用来解决什么样的问题
- 第四个考察点是实际应用中容易犯错的点
- 例如 == 与equals 的区别是什么
- 例如对象的强引用使用不当可能会导致内存泄露
- 那主要考察候选人对于不同对象引用方式的作用和理解
- 第五个考察点是与面试方向相关的知识点
- 例如面试的岗位是中间件研发
- 面试时可能会涉及更多的存储网络相关的知识考察