nuxt做多页面网站,电子商务网站建设的心得,千图网素材下载网站,怎么做网站平台梦想面试 Java 基础八股文十问十答第三期 作者#xff1a;程序员小白条#xff0c;个人博客 ⭐点赞⭐收藏⭐不迷路#xff01;⭐
21.说下Java8的Stream流的常用方法
答:
forEach遍历、find、match进行匹配reduce进行归约#xff0c;比如求和#xff0c;乘#xff0c;除聚合…面试 Java 基础八股文十问十答第三期 作者程序员小白条个人博客 ⭐点赞⭐收藏⭐不迷路⭐
21.说下Java8的Stream流的常用方法
答:
forEach遍历、find、match进行匹配reduce进行归约比如求和乘除聚合:max,min,count收集:collect: 1.统计summarizing,counting,averaging 2.groupingby,partitioningby 3.接合:joining 4.归约: reduce 5.归集 toList,toSet,toMap筛选: filter、映射: map 排序: sorted
22.说下ConcurrentHashMap原理
答:
ConcurrentHashMap是JDK1.5引入,在HashMap的基础上增加了线程安全的保障。
总结
做插入操作时首先进入乐观锁先计算得到哈希值然后在乐观锁中判断容器是否初始化如果没初始化则初始化容器如果已经初始化则判断该hash位置的节点是否为空如果为空则通过CAS操作进行插入失败则利用锁自选保证其成功。如果该节点不为空再判断容器是否在扩容中如果在扩容则帮助其扩容。如果没有扩容则进行最后一步先加锁然后判断是链表还是红黑树如果是链表找到hash值相同的那个节点(hash冲突)循环判断这个节点上的链表决定做覆盖操作还是插入操作如果是红黑树那么用红黑树的方式进行插入如果链表长度大于等于8数组长度大于等于64要进行树化。
23.Java8开始ConcurrentHashMap,为什么舍弃分段锁
通过 JDK 的源码和官方文档看来 他们认为的弃用分段锁的原因由以下几点
加入多个分段锁浪费内存空间。生产环境中 map 在放入时竞争同一个锁的概率非常小分段锁反而会造成更新等操作的长时间等待。为了提高 GC 的效率
24.ConcurrentHashMap(JDK1.8)为什么要使用synchronized而不是如ReentranLock这样的可重入锁
1锁的粒度
首先锁的粒度并没有变粗甚至变得更细了。每当扩容一次ConcurrentHashMap的并发度就扩大一倍。
2Hash冲突
JDK1.7中ConcurrentHashMap(通过二次hash的方式Segment - HashEntry能够快速的找到查找的元素。在1.8中通过链表加红黑树的形式弥补了put、get时的性能差距。JDK1.8中在ConcurrentHashmap进行扩容时其他线程可以通过检测数组中的节点决定是否对这条链表红黑树进行扩容减小了扩容的粒度提高了扩容的效率。
下面是我对面试中的那个问题的一下看法。
为什么是synchronized而不是ReentranLock
1减少内存开销
假设使用可重入锁来获得同步支持那么每个节点都需要通过继承AQS来获得同步支持。但并不是每个节点都需要获得同步支持的只有链表的头节点红黑树的根节点需要同步这无疑带来了巨大内存浪费。
2获得JVM的支持
可重入锁毕竟是API这个级别的后续的性能优化空间很小。synchronized则是JVM直接支持的JVM能够在运行时作出相应的优化措施锁粗化、锁消除、锁自旋等等。这就使得synchronized能够随着JDK版本的升级而不改动代码的前提下获得性能上的提升。
JDK1.7分段数组HashEntry数组链表JDK1.8Node数组链表红黑树
25.yml和properties的区别
yml是一种标记语言可以跨语言而properties只适用于SpringBoot项目。yml采用key:value 键值对形式,而properties是k-v格式yml采用UTF-8中文不会乱码但properties通过IO读取默认ISO-8859-1中文会产生乱码properties不保证加载顺序yml有先后加载顺序。先加载yml,再properties,相同配置properties会覆盖yml的配置。
26.类加载器有哪些
Java 中有以下四种类加载器: 引导类加载器 (Bootstrap ClassLoader): 也作根类加载器它用来加载 Java 的核心类是用原生代码来实现的并不继承自 java.lang.ClassLoader负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class由C实现不是ClassLoader子类。由于引导类加载器涉及到虚拟机本地实现细节开发者无法直接获取到启动类加载器的引用所以不允许直接通过引用进行操作。扩展类加载器extensions class loader它负责加载JRE的扩展目录lib/ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类。由Java语言实现父类加载器为null。系统类加载器system class loader被称为系统也称为应用类加载器它负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性或者CLASSPATH换将变量所指定的JAR包和类路径。程序可以通过ClassLoader的静态方法getSystemClassLoader()来获取系统类加载器。如果没有特别指定则用户自定义的类加载器都以此类加载器作为父加载器。由Java语言实现父类加载器为ExtClassLoader。
需要注意的是引导类加载器是最顶层的类加载器它不会受到类加载器层级的限制。因此如果引导类加载器无法加载所需的类则可以尝试使用其他类加载器进行加载。
27.类加载机制(三种)
JVM的类加载机制主要有如下3种。全盘负责所谓全盘负责就是当一个类加载器负责加载某个Class时该Class所依赖和引用其他Class也将由该类加载器负责载入除非显示使用另外一个类加载器来载入。双亲委派所谓的双亲委派则是先让父类加载器试图加载该Class只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲就是某个特定的类加载器在接到加载类的请求时首先将加载任务委托给父加载器依次递归如果父加载器可以完成类加载任务就成功返回只有父加载器无法完成此加载任务时才自己去加载。缓存机制。缓存机制将会保证所有加载过的Class都会被缓存当程序中需要使用某个Class时类加载器先从缓存区中搜寻该Class只有当缓存区中不存在该Class对象时系统才会读取该类对应的二进制数据并将其转换成Class对象存入缓冲区中。这就是为什么修改了Class后必须重新启动JVM程序所做的修改才会生效的原因。
28.类加载机制(什么时候类会被加载)
创建类的实例也就是new一个对象访问某个类或接口的静态变量或者对该静态变量赋值调用类的静态方法反射Class.forName(“com.lyj.load”)初始化一个类的子类会首先初始化子类的父类JVM启动时标明的启动类即文件名和类名相同的那个类
除此之外下面几种情形需要特别指出
对于一个final类型的静态变量如果该变量的值在编译时就可以确定下来那么这个变量相当于“宏变量”。Java编译器会在编译时直接把这个变量出现的地方替换成它的值因此即使程序使用该静态变量也不会导致该类的初始化。反之如果final类型的静态Field的值不能在编译时确定下来则必须等到运行时才可以确定该变量的值如果通过该类来访问它的静态变量则会导致该类被初始化。
29.HashMap 的长度为什么是 2 的幂次方
为了能让 HashMap 存取高效尽量较少碰撞也就是要尽量把数据分配均匀。我们上面也讲到了过了Hash 值的范围值-2147483648 到 2147483647前后加起来大概 40 亿的映射空间只要哈希函数映射得比较均匀松散一般应用是很难出现碰撞的。但问题是一个 40 亿长度的数组内存是放不下的。所以这个散列值是不能直接拿来用的。用之前还要先做对数组的长度取模运算得到的余数才能用来要存放的位置也就是对应的数组下标。这个数组下标的计算方法是“ (n - 1) hash”。n 代表数组长度。这也就解释了 HashMap 的长度为什么是 2 的幂次方。
这个算法应该如何设计呢
我们首先可能会想到采用%取余的操作来实现。但是重点来了“取余(%)操作中如果除数是 2 的幂次则等价于与其除数减一的与()操作也就是说 hash%lengthhash(length-1)的前提是 length 是 2 的 n 次方。” 并且 采用二进制位操作 相对于%能够提高运算效率这就解释了 HashMap 的长度为什么是 2 的幂次方。
30.LinkedList 为什么不能实现 RandomAccess 接口
RandomAccess 是一个标记接口用来表明实现该接口的类支持随机访问即可以通过索引快速访问元素。由于 LinkedList 底层数据结构是链表内存地址不连续只能通过指针来定位不支持随机快速访问所以不能实现 RandomAccess 接口。