没有合适的资源?快使用搜索试试~ 我知道了~
java八股文,Java八股文
资源推荐
资源详情
资源评论
Java⼋股⽂
⼀、Java 基础知识
1、Object 类相关⽅法
getClass 获取当前运⾏时对象的 Class 对象。
hashCode 返回对象的 hash 码。
clone 拷贝当前对象, 必须实现 Cloneable 接⼝。浅拷贝对基本类型进⾏值拷贝,对引⽤类型拷贝引⽤;深拷贝对基本类型进⾏值拷
贝,对引⽤类型对象不但拷贝对象的引⽤还拷贝对象的相关属性和⽅法。两者不同在于深拷贝创建了⼀个新的对象。
equals 通过内存地址⽐较两个对象是否相等,String 类重写了这个⽅法使⽤值来⽐较是否相等。
toString 返回类名@哈希码的 16 进制。
notify 唤醒当前对象监视器的任⼀个线程。
notifyAll 唤醒当前对象监视器上的所有线程。
wait 1、暂停线程的执⾏;2、三个不同参数⽅法(等待多少毫秒;额外等待多少毫秒;⼀直等待)3、与 Thread.sleep(long time) 相
⽐,sleep 使当前线程休眠⼀段时间,并没有释放该对象的锁,wait 释放了锁。
finalize 对象被垃圾回收器回收时执⾏的⽅法。
2、基本数据类型
整型:byte(8)、short(16)、int(32)、long(64)
浮点型:float(32)、double(64)
布尔型:boolean(8)
字符型:char(16)
3、序列化
Java 对象实现序列化要实现 Serializable 接⼝。
反序列化并不会调⽤构造⽅法。反序列的对象是由 JVM ⾃⼰⽣成的对象,不通过构造⽅法⽣成。
序列化对象的引⽤类型成员变量,也必须是可序列化的,否则,会报错。
如果想让某个变量不被序列化,使⽤ transient 修饰。
单例类序列化,需要重写 readResolve() ⽅法。
4、String、StringBuffer、StringBuilder
String 由 char[] 数组构成,使⽤了 final 修饰,是不可变对象,可以理解为常量,线程安全;对 String 进⾏改变时每次都会新⽣成⼀
个 String 对象,然后把指针指向新的引⽤对象。
StringBuffer 线程安全;StringBuiler 线程不安全。
操作少量字符数据⽤ String;单线程操作⼤量数据⽤ StringBuilder;多线程操作⼤量数据⽤ StringBuffer。
5、重载与重写
重载 发⽣在同⼀个类中,⽅法名相同,参数的类型、个数、顺序不同,⽅法的返回值和修饰符可以不同。
重写 发⽣在⽗⼦类中,⽅法名和参数相同,返回值范围⼩于等于⽗类,抛出的异常范围⼩于等于⽗类,访问修饰符范围⼤于等于⽗
类;如果⽗类⽅法访问修饰符为 private 或者 final 则⼦类就不能重写该⽅法。
6、final
修饰基本类型变量,⼀经出初始化后就不能够对其进⾏修改。
修饰引⽤类型变量,不能够指向另⼀个引⽤。
修饰类或⽅法,不能被继承或重写。
7、反射
在运⾏时动态的获取类的完整信息
增加程序的灵活性
JDK 动态代理使⽤了反射
8、JDK 动态代理
使⽤步骤
创建接⼝及实现类
实现代理处理器:实现 InvokationHandler ,实现 invoke(Proxy proxy,Method method,Object[] args) ⽅法
通过 Proxy.newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h) 获得代理类
通过代理类调⽤⽅法。
9、Java IO
普通 IO ,⾯向流,同步阻塞线程。
NIO,⾯向缓冲区,同步⾮阻塞。
⼆、Java 集合框架
1、List(线性结构)
ArrayList Object[] 数组实现,默认⼤⼩为 10 ,⽀持随机访问,连续内存空间,插⼊末尾时间复杂度 o(1),插⼊第 i 个位置时间复
杂度 o(n - i)。扩容,⼤⼩变为 1.5 倍,Arrays.copyOf(底层 System.ArrayCopy),复制到新数组,指针指向新数组。
Vector 类似 ArrayList,线程安全,扩容默认增长为原来的 2 倍,还可以指定增长空间长度。
LinkedList 基于链表实现,1.7 为双向链表,1.6 为双向循环链表,取消循环更能分清头尾。
2、Map(K,V 对)
HashMap
底层数据结构,JDK 1.8 是数组 + 链表 + 红⿊树,JDK 1.7 ⽆红⿊树。链表长度⼤于 8 时,转化为红⿊树,优化查询效率。
初始容量为 16,通过 tableSizeFor 保证容量为 2 的幂次⽅。寻址⽅式,⾼位异或,(n-1)&h 取模,优化速度。
扩容机制,当元素数量⼤于容量 x 负载因⼦ 0.75 时,容量扩⼤为原来的 2 倍,新建⼀个数组,然后转移到新数组。
基于 Map 实现。
线程不安全。
HashMap (1.7) 多线程循环链表问题
在多线程环境下,进⾏扩容时,1.7 下的 HashMap 会形成循环链表。
怎么形成循环链表: 假设有⼀ HashMap 容量为 2 , 在数组下标 1 位置以 A -> B 链表形式存储。有⼀线程对该 map 做 put 操
作,由于触发扩容条件,需要进⾏扩容。这时另⼀个线程也 put 操作,同样需要扩容,并完成了扩容操作,由于复制到新数组是头
部插⼊,所以 1 位置变为 B -> A 。这时第⼀个线程继续做扩容操作,⾸先复制 A ,然后复制 B ,再判断 B.next 是否为空时,由
于第⼆个线程做了扩容操作,导致 B.next = A,所以在将 A 放到 B 前,A.next ⼜等于 B ,导致循环链表出现。
HashTable
线程安全,⽅法基本全⽤ Synchronized 修饰。
初始容量为 11 ,扩容为 2n + 1 。
继承 Dictionary 类。
ConcurrentHashMap
线程安全的 HashMap。
1.7 采⽤分段锁的形式加锁;1.8 使⽤ Synchronized 和 CAS 实现同步,若数组的 Node 为空,则通过 CAS 的⽅式设置值,不
为空则加在链表的第⼀个节点。获取第⼀个元素是否为空使⽤ Unsafe 类提供的 getObjectVolatile 保证可见性。
对于读操作,数组由 volatile 修饰,同时数组的元素为 Node,Node 的 K 使⽤ final 修饰,V 使⽤ volatile 修饰,下⼀个节点也
⽤ volatile 修饰,保证多线程的可见性。
LinkedHashMap LinkedHashMap 继承⾃ HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红⿊树组成。另
外,LinkedHashMap 在上⾯结构的基础上,增加了⼀条双向链表,使得上⾯的结构可以保持键值对的插⼊顺序。
TreeMap 有序的 Map,红⿊树结构,可以⾃定义⽐较器来进⾏排序。
Collections.synchronizedMap 如何实现 Map 线程安全? 基于 Synchronized ,实际上就是锁住了当前传⼊的 Map 对象。
3、Set(唯⼀值)
HashSet 基于 HashMap 实现,使⽤了 HashMap 的 K 作为元素存储,V 为 new Object() ,在 add() ⽅法中如果两个元素的
Hash 值相同,则通过 equals ⽅法⽐较是否相等。
LinkedHashSet LinkedHashSet 继承于 HashSet,并且其内部是通过 LinkedHashMap 来实现的。
TreeSet 红⿊树实现有序唯⼀。
三、Java 多线程
1、synchronized
修饰代码块 底层实现,通过 monitorenter & monitorexit 标志代码块为同步代码块。
修饰⽅法 底层实现,通过 ACC_SYNCHRONIZED 标志⽅法是同步⽅法。
修饰类 class 对象时,实际锁在类的实例上⾯。
单例模式
public class Singleton {
private static volatile Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
偏向锁,⾃旋锁,轻量级锁,重量级锁
通过 synchronized 加锁,第⼀个线程获取的锁为偏向锁,这时有其他线程参与锁竞争,升级为轻量级锁,其他线程通过循环的⽅
式尝试获得锁,称⾃旋锁。若果⾃旋的次数达到⼀定的阈值,则升级为重量级锁。
需要注意的是,在第⼆个线程获取锁时,会先判断第⼀个线程是否仍然存活,如果不存活,不会升级为轻量级锁。
2、Lock
ReentrantLock
基于 AQS (AbstractQueuedSynchronizer)实现,主要有 state (资源) + FIFO (线程等待队列) 组成。
公平锁与⾮公平锁:区别在于在获取锁时,公平锁会判断当前队列是否有正在等待的线程,如果有则进⾏排队。
使⽤ lock() 和 unLock() ⽅法来加锁解锁。
ReentrantReadWriteLock
同样基于 AQS 实现,内部采⽤内部类的形式实现了读锁(共享锁)和写锁 (排它锁)。
⾮公平锁吞吐量⾼ 在获取锁的阶段来分析,当某⼀线程要获取锁时,⾮公平锁可以直接尝试获取锁,⽽不是判断当前队列中是否有线
程在等待。⼀定情况下可以避免线程频繁的上下⽂切换,这样,活跃的线程有可能获得锁,⽽在队列中的锁还要进⾏唤醒才能继续尝试
获取锁,⽽且线程的执⾏顺序⼀般来说不影响程序的运⾏。
3、volatile
Java 内存模型
剩余18页未读,继续阅读
资源评论
emma20080101
- 粉丝: 1070
- 资源: 5281
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功