以下是常见的 Java 八股文内容,涵盖了 Java 基础、并发编程、JVM、IO 与 NIO、框架等方面:
Java 基础
-
Java 中序列化是怎么实现的呢?
-
实现
Serializable
接口,就会实现数据序列化的效果。 -
调用 JSON 做序列化,如 Jackson、fastjson 等。
-
实现
Externalizable
接口,就可以实现反序列化的效果。
-
-
java的流有哪些呢?
-
从方向方面,主要就是输入流和输出流。
-
从单位方面,主要就是分为字节流和字符流。字节流主要就是
InputStream
,OutputStream
。字符流主要就是Reader
,Writer
。
-
-
抽象类和接口有什么区别呢?
-
从方法编写方面,抽象类中可以有抽象方法和普通方法,而接口中只能编写抽象方法。
-
从继承和实现方面,抽象类只能继承一个类并且可以实现多个接口,而接口可以继承多个接口。
-
在变量的定义方面,接口只能定义静态变量,抽象类可以定义普通变量和静态变量。
-
-
final关键值有了解过吗?
-
在修饰方法的时候,说明该方法无法被重写。
-
在修饰类的时候,说明该类无法被继承。
-
在修饰属性的时候,说明该变量从创建到销毁过程中不会改变。
-
在修饰形参的时候,说明该形参的引用在方法执行前后都会不发生改变。
-
-
java中共享变量有哪些?
-
静态变量。
-
使用
volatile
修饰 Java 中的变量就会变成共享变量。
-
-
编写singleton函数?(单例模式)
-
饿汉式:
java复制
public class Singleton { private final static Singleton instance = new Singleton(); public Singleton getInstance() { return instance; } }
-
懒汉式:
java复制
public class Singleton { private static Singleton instance; public Singleton getInstance() { return instance == null ? new Singleton() : instance; } }
-
并发编程
-
并发编程三要素?
-
原子性:一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行。
-
可见性:多个线程操作一个共享变量时,其中一个线程对变量进行修改后,其他线程可以立即看到修改的结果。
-
有序性:即程序的执行顺序按照代码的先后顺序来执行。
-
-
实现可见性的方法有哪些?
-
synchronized
或者Lock
:保证同一个时刻只有一个线程获取锁执行代码,锁释放之前把最新的值刷新到主内存,实现可见性。
-
-
线程 B 怎么知道线程 A 修改了变量
-
volatile
修饰变量。 -
synchronized
修饰修改变量的方法。 -
wait/notify
。 -
while
轮询。
-
-
synchronized、volatile、CAS 比较
-
synchronized
是悲观锁,属于抢占式,会引起其他线程阻塞。 -
volatile
提供多线程共享变量可见性和禁止指令重排序优化。 -
CAS
是基于冲突检测的乐观锁(非阻塞)。
-
-
sleep 方法和 wait 方法有什么区别?
-
sleep
方法和wait
方法都可以用来放弃 CPU 一定的时间,不同点在于如果线程持有某个对象的监视器,sleep
方法不会放弃这个对象的监视器,wait
方法会放弃这个对象的监视器。
-
-
ThreadLocal 是什么?有什么用?
-
ThreadLocal
是一个本地线程副本变量工具类。主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的变量值完成操作的场景。
-
-
为什么 wait()方法和 notify()/notifyAll()方法要在同步块中被调用
-
这是 JDK 强制的,
wait()
方法和notify()/notifyAll()
方法在调用前都必须先获得对象的锁。
-
-
多线程同步有哪几种方法?
-
Synchronized
关键字,Lock
锁实现,分布式锁等。
-
JVM
-
Serial 垃圾收集器:单线程、复制算法。
-
ParNew 垃圾收集器:
Serial+
多线程。 -
Parallel Scavenge 收集器:多线程复制算法、高效。
-
Serial Old 收集器:单线程标记整理算法。
-
Parallel Old 收集器:多线程标记整理算法。
-
CMS 收集器:多线程标记清除算法。
-
G1 收集器。
-
JVM 类加载机制:类加载器、双亲委派、OSGI(动态模型系统)、动态改变构造、模块化编程与热插拔。
-
JVM 内存模型:本地方法栈、程序计数器、堆、方法区、分代回收、堆和栈的区别、什么时候会触发 FullGC、什么是 Java 虚拟机、为什么 Java 被称作是“平台无关的编程语言”、对象分配规则、描述一下 JVM 加载 class 文件的原理机制、Java 对象创建过程。
IO 与 NIO
-
Java 中 IO 流?
-
Java 中有多种 IO 流,包括字节流(
InputStream
、OutputStream
)和字符流(Reader
、Writer
)等。
-
-
Java IO 与 NIO 的区别
-
Java IO 是面向流的,NIO 是面向缓冲区的。
-
Java IO 是阻塞 IO,NIO 支持非阻塞 IO。
-
NIO 有通道(Channel)和缓冲区(Buffer)的概念,可以提供更高效的 IO 操作。
-
-
常用 io 类有哪些
-
常用的 IO 类包括
FileInputStream
、FileOutputStream
、BufferedReader
、BufferedWriter
等。
-
-
字节流与字符流的区别
-
字节流用于处理二进制数据,字符流用于处理文本数据。
-
字节流的读写操作是以字节为单位,字符流的读写操作是以字符为单位。
-
-
阻塞 IO 模型
-
在用户线程要获取内核中获取数据,而此时内核中没有数据,用户线程就会等待从而导致用户线程阻塞,当内核中有数据后,数据需要从内核缓冲区复制到用户缓冲区,在这个过程中用户线程也需要等待从而导致线程堵塞。在这两个阶段中用户线程都是堵塞的,这就是阻塞 IO。
-
-
非阻塞 IO 模型
-
用户线程要从内核中获取数据,但内核中没有数据,此时内核直接返回错误信息给用户线程,反之线程堵塞,用户线程会循环的调用内核的方法直到内核中有数据,当内核中有数据后,用户线程就会等待内核缓冲区中的数据复制到用户缓冲区中,此时用户线程是阻塞的。在第一阶段是不阻塞的,而第二阶段是堵塞的,这就是非阻塞 IO。
-
-
多路复用 IO 模型
-
多路 IO 复用模型允许一个线程处理多个 IO 操作,通过使用
select
、poll
或epoll
等系统调用,可以同时监听多个文件描述符的 IO 事件,当某个文件描述符有 IO 事件发生时,就可以进行相应的处理。
-
-
信号驱动 IO 模型
-
信号驱动 IO 模型使用信号来通知应用程序有 IO 事件发生,应用程序在收到信号后,可以进行相应的处理。
-
-
异步 IO 模型
-
异步 IO 模型允许应用程序发起 IO 请求后,立即返回继续执行其他任务,当 IO 操作完成时,会通过回调函数等方式通知应用程序。
-
-
JAVA NIO
-
Java NIO(New IO)是 Java 提供的一套新的 IO API,它提供了更高效的 IO 操作方式,包括非阻塞 IO、通道和缓冲区等概念。
-
-
NIO 的缓冲区
-
NIO 的缓冲区(Buffer)是用于存储数据的容器,可以是字节缓冲区、字符缓冲区、整数缓冲区等。缓冲区有容量(capacity)、位置(position)和限制(limit)等属性。
-
-
NIO 的非阻塞
-
NIO 支持非阻塞 IO 操作,可以通过设置通道(Channel)为非阻塞模式,然后使用选择器(Selector)来监听多个通道的 IO 事件。
-
-
Channel
-
NIO 的通道(Channel)是用于表示 IO 源或目标的对象,可以是文件通道、套接字通道等。通道可以进行读写操作,并且支持非阻塞模式。
-
-
Buffer
-
NIO 的缓冲区(Buffer)是用于存储数据的容器,可以是字节缓冲区、字符缓冲区、整数缓冲区等。缓冲区有容量(capacity)、位置(position)和限制(limit)等属性。
-
框架
-
Spring 中的设计模式有哪些?
-
工厂模式:常见的工厂模式主要就是
BeanFactory
(延迟注入)和ApplicationContext
(完全注入),我们无需知道类如何创建,直接从工厂中获取即可。 -
单例模式:IOC 默认情况下就是一个单例模式,每次获取相同的类的时候,获取的对象是同一个。不会进行多次的创建。单例模式还分为饿汉式(主动创建单例)及懒汉式(需要时再创建单例)。
-
代理模式:AOP 是采用代理模式来实现的。当要代理的对象实现接口的时候,我们就会使用
JDK Proxy
来生成代理对象。如果代理的对象没有实现接口的话,我们就会使用CGLIB
生成一个被代理对象的子类作为代理对象。 -
策略模式:在编写项目的时候就有使用到策略模式,因为要控制分布式锁的失败策略,会在枚举类编写一个抽象方法,编写多个内部方法去重写该方法,不同的内部方法就是不同的策略。
-
责任链模式:Stream 流就是使用该模式的,按照对应的顺序去执行方法,并向下传递对象。起到解耦合的作用。
-
-
事务的传播性有哪些?
-
Propagation_Required
:如果 B 为 A 的子方法,并且都为该传播类型,那么它们都会在同一个事务中。如果主方法中没有开启事务的话就会开启新事务。 -
Propagation_Required_new
:如果 B 为 A 子方法,B 会创建一个独立的事务,B 不会受 A 事务的影响。 -
Propagation_nested
:如果 B 为 A 子方法,B 会创建一个事务内嵌到 A 的事务中,如果 A 中没有事务的话,就单独开启一个事务。
-
-
@Transactional 的原理有了解过嘛?
-
事务注解是基于 AOP 来实现的,也就是在执行方法前开启事务,如果
try/catch
捕获到异常的话就会进行回滚,在方法执行完成后就会进行提交。AOP 实现涉及到动态代理的流程。如果被代理目标对象实现了接口的话,就会使用JDK Proxy
生成代理对象。如果代理对象没有实现接口的话,就会使用CGLIB Proxy
生成被代理对象的子类作为代理对象。
-
-
说说 CGLIB 的执行流程?
-
CGLIB 是一个强大的高性能代码生成库,它可以在运行期动态生成新的类。在使用 CGLIB 时,首先需要创建一个实现
Enhancer
类的对象,然后设置要增强的类和方法,最后通过create()
方法生成代理对象。CGLIB 会使用字节码技术生成新的类,并在运行时加载到 JVM 中。
-