1.动态代理的基本原理和实现
- 动态代理是不事先为每个需要被代理的类编写代理类,而是在运行时生成代理对象,通过代理对象间接访问目标对象,实现对目标对象的增强或者控制,java使用反射创建代理类
- 实现的两个核心类
- Proxy类
- invocationHandler接口
- 实现方式
- 创建一个代理类实现invocationHandler接口,重写invoke方法,实现相关逻辑
- 客户端通过Proxy.newProxyInstance方法来创建代理对象
2.Mysql联合索引讲一下,假设我用abc三个字段建联合索引,我用ac查,那么走不走联合索引?为什么?
- 联合索引是多个字段组成的索引
- 使用ac查找,不会走abc联合索引,因为不符合最左前缀原则。
3.jdk1.7和1.8中的hashmap的区别
- 数据结构
- jdk1.7使用数组+链表
- jdk1.8使用数组+链表/红黑树;数组长度大于64且链表长度大于8时,由链表转换为红黑树
- 节点的插入方法
- jdk1.7 头插法
- jkd1.8 尾插法;为了解决多线程的链表死循环问题
- 节点hash值
- jkd1.7 hash值可变
- jkd1.8 hash是final修饰的,不可变
比较 | HashMap1.7 | HashMap1.8 |
---|---|---|
数据结构 | 数组+链表 | 数组+链表+红黑树 |
节点 | Entry | Node TreeNode |
Hash算法 | 较为复杂 | 异或hash右移16位 |
对Null的处理 | 单独写一个putForNull()方法处理 | 作为以一个Hash值为0的普通节点处理 |
初始化 | 赋值给一个空数组,put时初始化 | 没有赋值,懒加载,put时初始化 |
扩容 | 插入前扩容 | 插入后,初始化,树化时扩容 |
节点插入 | 头插法 | 尾插法 |
3.1为何hashmap中的扩容是<<1?
- <<1是左移一位的位运算,运算效率比 *2 要高
- 计算数组下标位置时,使用(n-1)&hash,2的幂次方-1后,二进制低位都是1,按位与运算效率比 hash%n 要高
3.2讲一下hashmap的扩容步骤?
- 当数组大小达到阈值capacity*loadFactor的大小时进行扩容
- 一般情况下table容量和阈值都扩大2倍
- 使用(hash高位 & newCap-1)计算新的数组下标,并放入链表
3.3ConcurrentHashMap的put流程?
- 获取key的hashCode,调用扰乱函数,获取hash值
- 使用hash值&(数组长度-1)得到数组下标
- 检测找到的数组位置是否有节点,没有直接放入
- 如果有节点那么要上锁
- jdk1.7底层结构是分段数组+链表,使用Segment锁(实现了ReentrantLock)分段上锁
- jdk1.8底层结构式节点数组+链表/红黑树,使用synchronized配合CAS给链表头节点或红黑树头节点上锁
- 使用equal方法查找有没有一样的key的节点,如果有直接覆盖,没有就插jkd1.7头插,jkd1.8尾插。
4.方法区和永久代的关系?为什么要将元空间(MetaSpace) 替换为永久代 (PermGen) 呢?
- 永久代是方法区的在jdk1.7之前的实现。
- 避免OOM异常
- 元空间存在于本地内存,意味着只要本地内存足够,它不会出现像永久代中“java.lang.OutOfMemoryError: PermGen space”这种错误。
- Metaspace 区域位于堆外,所以它的最大内存大小取决于系统内存,而不是堆大小。
5.Java中有哪些锁?简单介绍了一下两种锁的优缺点
- 有synchronized锁和reentrantlock可重入锁
优缺点 | synchronized锁 | reentrantlock可重入锁 |
---|---|---|
都是可重入的 | ||
修饰内容 | 普通方法、静态方法和代码块 | 只能用在代码块上 |
加锁释放锁 | 自动加锁,自动释放 | 手动调用lock()上锁,unlock()释放锁 |
锁类型 | 只有非公平锁 | 默认非公平锁,可以换成公平锁 |
响应中断 | 无法响应中断,发生死锁会一直等待 | 可以响应中断并释放锁,解决了死锁问题 |
实现方式 | Monitor管程机制 JVM层面 | AQS的管程机制 JDK的API层面 |
6.Java对象创建到销毁的流程
- 检查类加载
- 加载:读取class文件的二进制字节流,创建java.lang.Class对象,将类信息存入方法区
- 连接
- 验证
- 文件格式验证
- 元数据验证
- 字节码验证
- 符号引用验证
- 准备:给静态变量赋零值
- 解析:将符号引用转换为直接引用
- 验证
- 初始化:给静态变量赋初始值
- 分配内存空间
- 初始化零值
- 设置对象头
- 执行init方法
- 使用:对象至少存在一个强引用
- 销毁:对象不存在任何引用,处于不可达状态,将会被垃圾回收,释放内存
7.给定10亿条url,内存有限,怎么快速找出其中一条?
- 使用哈希索引结构(无内存大小限制时)
- 使用布隆过滤器(能判断出哪个不存在)
- 使用外部排序算法:将10亿条url分成若干小组,在小组中进行排序,最终使用二分法进行查找
8.索引失效的场景有哪些?
- 不满足最左前缀原则
- like以%开头
- 想命中联合索引时,where语句没有包含索引最左字段。
- 使用where a = b语句时
- a部分使用了运算符
- a部分使用了函数
- b部分数据类型不匹配
- 使用or时,or前后的语句有至少一个没命中索引
9.http如何跨域?tcp如何长链接?
- 两种跨域方式
- jsonP
- CORS
- tcp长连接:节约了建立连接与销毁连接的开销
- 三次握手建立连接
- 通过心跳机制:互相发送心跳消息检测对方存活的状态
- 一定事件内没有收到对方的心跳包,将会断开连接
10.(HR面)你觉得大学生活给你带来了什么?
- 根据经历边聊边回答
- 使用具体例子丰满自己的人设
- 这不是一个填空题,而是一个问答题