java基础(持续更新)
2022-03-07 18:06:32 0 举报
AI智能生成
登录查看完整内容
点我主页,涵盖 Java 后面面试所有知识点,本人持续整理,目前已帮助20+人拿到 大厂Offer
作者其他创作
大纲/内容
阻塞添加 所谓的阻塞添加是指当阻塞队列元素已满时,队列会阻塞加入元素的线程,直到队列元素不满时才重新唤醒线程执行元素加入操作。阻塞删除 阻塞删除是指在队列元素为空时,删除队列元素的线程将被阻塞,直到队列不为空再执行删除操作(一般都会返回被删除的元素)
阻塞队列:BLockingQueue
常见面试题
LinkedList - 链表实现
最小初始容量 11
超过 11 使用 System.arrayCopy 一个新数组,进行 1.5 倍扩容 -- oldCapacity + (oldCapacity >> 1)
List 扩容?
高并发写时,CopyOnWriteArrayList为何这么慢呢?因为其每次add时,都用Arrays.copyOf创建新数组,频繁add时内存申请释放性能消耗大。
CopyOnWriteArrsyList
如何解决?
ArrayList 线程安全问题?
知乎专栏
ArrayList - 数组实现
hashSet - hashmap实现,
Collection 大家族
拉链法
内置多个 hash 算法,一个冲突就用另一个
双重散列法
如果发现了冲突,就按照制定的策略从这个位置往后找,直到找到有空的位置存储
开方寻址法
hash 冲突的几种解决方式;
哈希表哪家强?几大编程语言吵起来了!
推荐这一种嗷
map.entrySet()
map.keySet()
Map 遍历
Map家族中最常使用的一个。
问:为什么计算出hascode 后不直接与数组长度取模?模运算的消耗还是比较大的!
HashMap 定位数组索引位置:这里的Hash算法本质上就是三步:取key的hashCode值、高位运算。
1. 确定哈希桶数组索引位置
时序图分析
2. 分析HashMap的put方法
为什么需要扩容?
扩容的负载因子是 0.75,即当数组容量cap大小达到 cap x 0.75 就会扩容 2 倍
据我的经验,日常使用中,大部分使用到 HashMap 的情况,大小都不会超过 1000
3. 扩容机制- put 方法(得物)
底层实现: 数组+链表+红黑树。
单链表如何翻转?(不借助其它数据结构)
因为 jdk7 在扩容的时候认为新插入的元素访问概率更高,所以在扩容时,会把链表翻转。所以在多线程下就会形成hash环
java7 中put 操作 的 resize 容易出现 死循环,会在数组上形成一个环形链表。
jdk 7 头插法为什么会产生hash 环?
jdk 7 头插法
jdk 8 尾插法 解决hash 环
java8 中是如何解决 hash 环问题的?
hashmap8如何解决hashmap7中的环链问题
Hash 环问题
多线程
共享资源
并发安全问题分析:
采用分段锁,每一段数据分配一个Segment(锁),当线程占用其中一个Segment时,其他线程可正常访问其他段数据Segment 继承了ReentrantLock,是一个AQS对象
虽然已经解决了HashMap并发安全问题,但是查询遍历链表效率太低。
底层实现
java1.7
抛弃了原有的 Segment 分段锁,而采用了 CAS + volatile 来保证并发安全性。
8中如何解决并发的
java 1.8
总结:
java1.7 和 java1.8实现不同
HashMap? ConcurrentHashMap? 相信看完这篇没人能难住你!
ConcurrentHashMap
线程安全的HashMap(并发包提供的,不属于Map体系)
一直 put
扩容时
HashMap 什么情况下会发生 OOM?
HashMap 为什么在链表长度为 8 的时候转红黑树,为啥不能是 9 是 10?
1.table 的初始化时机是什么时候 一般情况下,在第一次 put 的时候,调用 resize 方法进行 table 的初始化(懒初始化,懒加载思想在很多框架中都有应用!) 初始化的 table.length 是多少、阀值(threshold)是多少,实际能容下多少元素 默认情况下,table.length = 16; 默认情况下,threshold = 12; 默认情况下,能存放 12 个元素,当存放第 13 个元素后进行扩容
// oldCap左移一位; newCap = 16 << 1 = 32;
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && // oldCap左移一位; newCap = 16 << 1 = 32; oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold // newThr = 12 << 1 = 24;
2.什么时候触发扩容,扩容之后的 table.length、阀值各是多少 当 font color=\"#f15a23\
3.table 的 length 为什么是 2 的 n 次幂? 为了利用位运算 & 求 key 的下标(我们可以发现,只有 & 数是1时,& 运算的结果与被 & 数一致)1&1=1;0&1=0;1&0=0;0&0=0;为什么为什么要先高16位异或低16位再取模运算? 右移·16 位 再异或运算,就能保证高低位都参与到取模运算中;而取模运算 是通过 hash&(length-1)实现的!只是为了降低hash冲突的几率(看图)
4.求索引的时候为什么是:hash&(length-1),而不是 hash&length,更不是 hash%lengthhash%length 效率不如位运算快hash%length 会提高碰撞几率,导致 table 的空间得不到更充分的利用、降低 table 的操作效率原理:为了利用位运算 & 求 key 的下标(我们可以发现,只有 & 数是1时,& 运算的结果与被 & 数一致)1&1=1;0&1=0;1&0=0;0&0=0;
5.数组大小需要保证是 2 的 N 次幂!!!从构造方法的逻辑可以看出,HashMap 并不是直接使用外部传递进来的 initialCapacity,而是经过了 tableSizeFor() 方法的处理,再赋值到 threshole 上。在 tableSizeFor() 方法中,通过逐步位运算,就可以让返回值,保持在 2 的 N 次幂。以方便在扩容的时候,快速计算数据在扩容后的新表中的位置。那么当我们从外部传递进来 1w 时,实际上经过 tableSizeFor() 方法处理之后,就会变成 2 的 14 次幂 16384,再算上负载因子 0.75f,实际在不触发扩容的前提下,可存储的数据容量是 12288(16384 * 0.75f)。
6.为什么加载因子的默认值是 0.75,并且不推荐我们修改 如果loadFactor太小,那么map中的table需要不断的扩容,扩容是个耗时的过程 如果loadFactor太大,那么map中table放满了也不不会扩容,导致冲突越来越多,解决冲突而起的链表越来越长,效率越来越低 而 0.75 这是一个折中的值,是一个比较理想的值
7.HashMap在并发编程环境下有什么问题啊?(1)多线程扩容,引起的死循环问题 --》 1.7 头插法(2)多线程put的时候可能导致元素丢失(3)put非null元素后get出来的却是null
8. 链表转红黑树的阈值为什么选8?为什么用红黑树做优化?font color=\"#f15a23\
1、table 的初始化时机是什么时候,初始化的 table.length 是多少、阀值(threshold)是多少,实际能容下多少元素2、什么时候触发扩容,扩容之后的 table.length、阀值各是多少?3、table 的 length 为什么是 2 的 n 次幂?为什么为什么要先高16位异或低16位再取模运算?4、求索引的时候为什么是:h&(length-1),而不是 h&length,更不是 h%length5、 Map map = new HashMap(1000); 当我们存入多少个元素时会触发map的扩容; Map map1 = new HashMap(10000); 我们存入第 10001个元素时会触发 map1 扩容吗? 会的,动态扩容! 最大容量为: 1024*0.75 。6、为什么加载因子的默认值是 0.75,并且不推荐我们修改7. HashMap 多线程会有什么问题?8. 链表转红黑树的阈值为什么选8?为什么用红黑树做优化?
JDK7: 死循环-> 头插法
0. HashMap 并发情况下会有什么线程安全问题?
好处:
坏处:
JDK 7:Segment(分段锁)+HashEntry
JDK8 中放弃了 Segment 采用了 Node 这个数据结构每个键值对(key-value)都存储在一个Node中。同时Node也有一些子类,TreeNodes用于树结构中(当链表长度大于8时转化为红黑树);TreeBins用于维护TreeNodes。当链表转树时,用于封装TreeNode。也就是说,ConcurrentHashMap的红黑树存放的是TreeBin,而不是treeNode————————————————版权声明:本文为CSDN博主「Coding-ls」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/programerxiaoer/article/details/80040090
JDK8: CAS+volatile +sychronized
1. ConcurrentHashMap的实现原理:
初始化数组
1:首先判断是否初始化,如果没有初始化则进入$3进行初始化工作 2:如果已经初始化了,进入无限循环,$4原子判断key对应的数组下标是否有值了(font color=\"#f15a23\
4. ConcurrentHashMap的put()方法?
5.ConcurrentHashmap 不支持 key 或者 value 为 null 的原因?
有序性
可见性
底层通过内存屏障来实现
通俗的讲就是: a happen-before b,则a所做的任何操作对b是可见的。
happend-before 原则:
volatile 总线风暴知道不?
引申 volatile 面试发问?
11.经典面试题:为什么 ConcurrentHashMap 的读操作不需要加锁?
ConcurrentHashMap:0. HashMap 并发情况下会有什么线程安全问题?1. ConcurrentHashMap的实现原理2. ConcurrentHashMap1.7和1.8的区别?3. ConcurrentHashMap使用什么技术来保证线程安全4. ConcurrentHashMap的put()方法5. ConcurrentHashmap 不支持 key 或者 value 为 null 的原因?6. put()方法如何实现线程安全呢?7. ConcurrentHashMap扩容机制8. ConcurrentHashMap的get方法是否要加锁,为什么?9. 为什么使用ConcurrentHashMap10. ConcurrentHashMap迭代器是强一致性还是弱一致性?HashMap呢?11. 经典面试题:为什么 ConcurrentHashMap 的读操作不需要加锁?
Java 8系列之重新认识HashMap
HashMap
HashMap线程不安全,HashTable虽然线程安全,但性能差,那怎么破?使用ConcurrentHashMap类吧,既线程安全,还操作高效,谁用谁说好。
线程安全。遗留类,不再建议使用。被下面两个代替。线程安全的的情况下使用:HashMap替代线程不安全的情况下使用: ConCurrentHashMap 代替
Hashtable
保证了元素插入的顺序。
LinkedHashMap
SortedMap的子类,键支持排序。
TreeMap
Map 大家族
集合框架:Collection 和 Map
与 或 非 异或 ?
System.out.println(3|9)输出什么?
Linux 基础命令
public final native Class<?> getClass()//native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写。public native int hashCode() //native方法,用于返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap。public boolean equals(Object obj)//用于比较2个对象的内存地址是否相等,String类对该方法进行了重写用户比较字符串的值是否相等。protected native Object clone() throws CloneNotSupportedException//naitive方法,用于创建并返回当前对象的一份拷贝。一般情况下,对于任何对象 x,表达式 x.clone() != x 为true,x.clone().getClass() == x.getClass() 为true。Object本身没有实现Cloneable接口,所以不重写clone方法并且进行调用的话会发生CloneNotSupportedException异常。public String toString()//返回类的名字@实例的哈希码的16进制的字符串。建议Object所有的子类都重写这个方法。public final native void notify()//native方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。public final native void notifyAll()//native方法,并且不能重写。跟notify一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。public final native void font color=\"#f15a23\
Object 类有哪些方法?
主要是为了配合基于散列的集合一起使用。
hashCode()方法的作用?
“设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该产生同样的值。如果在将一个对象用put()添加进HashMap时产生一个hashCdoe值,而用get()取出时却产生了另一个hashCode值,那么就无法获取该对象了。所以如果你的hashCode方法依赖于对象中易变的数据,用户就要当心了,因为此数据发生变化时,hashCode()方法就会生成一个不同的散列码”。
回答一:与集合有关,比如Map 的get 和 put 操作,都依赖与 hashCode方法
这个问题主要是针对映射相关的操作(Map接口)。学过数据结构的同学都知道Map接口的类会使用到键对象的哈希码,当我们调用put方法或者get方法对Map容器进行操作时,都是根据键对象的哈希码来计算存储位置的,因此如果我们对哈希码的获取没有相关保证,就可能会得不到预期的结果。
回答二:
因为如果只重写了 equals 方法,两个对象 equals 返回了true,但是如果没有重写 hashCode 方法,集合还是会插入元素。这样集合中就出现了重复元素了。
说白了就是 hashmap 在put 的时候 既用到了 hashcode 计算索引下标,又用到了 equlas 判断对象是否相等。
回答三:从equals 注释角度
我们看一下Object类中关于hashCode()方法的注释1.在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 2.如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。 3.如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
其实 equals 的javadoc 注释上就已经说的很清楚了
重写 equals 为甚要重写 hashcode 方法?一图胜千言(图)
hashcode()
比较值
基本类型
比较内存地址
引用类型
==
回答: 默认情况下也就是从超类Object继承而来的equals方法与‘==’是完全等价的,比较的都是对象的内存地址,但我们可以重写equals方法,使其按照我们的需求的方式进行比较,如String类重写了equals方法,使其比较的是字符的序列,而不再是内存地址。
== 和equlas()有什么区别?
线程安全:String 使用太广泛了,与其费劲心思的给它加锁让他线程安全,不如直接不可变来的直接。
安全,安全,还是他妈的安全!
像下面这样字符串one和two都用字面量\"something\"赋值。它们其实都指向同一个内存地址。
效率,效率,还是他妈的效率。
String 为什么设计为不可变的?
线程安全:底层 sychronized 修饰
StringBuffer
StringBuilder
String
long:32/64 位,8 个字节
int:32/64 位,4 个字节
byte:8 位,1 个字节
+= 操作会把运算结果,强制转换为持有结果的类型,即 把 a+b 的 结果强制转换为 a 类型
a=a+b 和 a+=b 的区别?
如何通过反射创建对象?
首先通过对象类的 getDeclaredField(“name”) 方法获取 Field 对象;再通过 调用 field.setAccessible(true) 把字段设置为可访问;最后,通过 field 的 get、set 方法获取或者设置字段值。
如何通过反射获取和设置对象的私有字段?
反射
两者的出现都是用来提高GC 效率的。SoftReference 在内存不足要发生 GC 前时会被回收WeakReference 一旦发生GC,无论内存是否足够,都会回收被 弱引用关联的对象;
java 中 weakReference 和 SoftReference 的区别?
public static final 修饰的变量也就是我们所说的编译期常量,这些变量在编译器就会被替换掉,因为编译器知道这些变量的值在运行时不会再改变了。但是:当引用第三方 jar 包里的编译器常量版本改变时,确保你的项目要重新编译哦!
java 中的编译期常量指的是什么?有什么要注意的地方?
1. Jstack [java pid]:在当前终端显示,也可以重定向到文件中。
2. JvisualVM:Thread Dump:图形化界面操作
如何在java 中获取线程堆栈?
创建型
结构型
行为型
结合病历模块化改造详细谈:策略+工厂模式
什么是模板方法模式?
举出一个如何开闭原则模式的例子?
你在工作中使用到过什么设计模式?
设计模式
构造器注入和 setter 注入优缺点?
二分查找
基础算法
java基础
OSI
DNS 域名解析,得到IP地址
www.baidu.com
三次握手,成功建立连接
进行 Http 请求
页面渲染,响应请求
服务器收到请求
TCP 四次挥手
关闭连接
一次完整的网络请求流程?从输入网址到浏览器呈现页面内容,中间发生了什么?
子主题
三次握手
四次挥手
为什么需要四次挥手?
TCP 握手和挥手?
HTTP只是个行为准则,而TCP才是GET和POST怎么实现的基本。
GET和POST两种基本请求方法有什么区别?
Linux 提供了 I/O 复用函数 select/poll/epoll,进程将一个或多个读操作通过系统调用函数,阻塞在函数操作上。这样,系统内核就可以帮我们侦测多个读操作是否处于就绪状态
select: 1024 个文件描述符
pool 与 select 类似,只不过没有了数量限制,但是当 文件描述符太多时还是有性能问题
epool:用红黑树存储 文件描述符 存放问题
I/O 复用
NIO
网络
前中后序遍历
平衡二叉树:平衡二叉树是基于二分法的策略提高数据的查找速度的二叉树的数据结构;
B树和平衡二叉树稍有不同的是B树属于多叉树又名平衡多路查找树(查找路径不只两个),数据库索引技术里大量使用者B树和B+树的数据结构
B树
B+树是B树的一个升级版,相对于B树来说B+树更充分的利用了节点的空间,让查询速度更加稳定,其速度完全接近于二分法查找。为什么说B+树查找的效率要比B树更高、更稳定;
B+树
本质上就是一个会自动调整树高度的 二叉查找树
红黑树(TreeMap , TreeSet)
树的发展史
树
翻转
链表
java 中 统计一个文件中出现频率最高的单词?
检查两个给定的字符串是反序的?
a=a+b;\tb=a-b;\ta=a-b;
加减法
a=a*b;\tb=a/b;\ta=a/b;
乘除法
a=a^b;\tb=a^b;\ta=a^b;
异或法
在不使用临时变量的情况下,如何交换两个整数变量的值?
字符串
算法
JAVA
0 条评论
回复 删除
下一页