(持续更新)Java八股文-会一个记一个篇

一、Java基础篇

1、接口和抽象类的区别
(1)抽象类可以有工造方法,而接口没有
(2)抽象类可以有抽象方法和具体方法,接口只能有抽象方法
(3)抽象类的成员4种权限修饰符都可以修饰,而接口只能用private
2、重载和重写的区别
重载发生在同一个类中,方法名相同,参数列表、返回类型、权限修饰符可以不同

重写发生在子类中,方法名、参数列表、返回类型都相同,权限修饰符要大于父类方法,声明异常范围要小于父类方法,但是final和private修饰的方法不可重写
3、==和equals的区别
==比较基本类型,比较的是值,equals比较引用类型,比较的是内存地址

equals是Object类的方法,本质上和==一样,但是有些类重写了equals方法,比如String的equals被重写后,比较的是内存地址,另外重写了equals后,也必须重写hashcode()方法
4、异常处理机制
(1)使用try、catch、finally、捕获异常,finally中的代码一定会执行,捕获异常后程序会继续执行
(2)使用throws声明该方法可能会抛出的异常类型,出现异常后,程序终止
5、HashMap原理
1、HashMap在Jdk1.8以后是基于数组+链表+红黑树来实现的,特点是key不能重复,可以为null,线程不安全

2、HashMap的扩容机制:HashMap的默认容量为16,默认的负载因子为0.75,当HashMap中元素个数超过容量乘以负载因子的个数时,就创建一个大小为前一次两倍的新数组,再将原来数组中的数据复制到新数组中。当数组长度达到64且链表长度大于8时,链表转为红黑树

3、HashMap存取原理:
(1)计算key的hash值,然后进行二次hash,根据二次hash结果找到对应的索引位置
(2)如果这个位置有值,先进行equals比较,若结果为true则取代该元素,若结果为false,就是用高低位平移法将节点插入链表(JDK8以前使用头插法,但是头插法在并发扩容时可能会造成环形链表或数据丢失,而高低位平移法会发生数据覆盖的情况)
6、想要线程安全的HashMap怎么办?
(1)使用ConcurrentHashMap
(2)使用HashTable
(3)Collections.synchronizedHashMap()方法
ConcurrentHashMap原如何保证的线程安全?
JDK1.7:使用分段锁,将一个Map分成了16个段,每个段都是一个小的hashmap,每次操作只对其中一个段加锁

JDK1.8:采用CAS(乐观锁)+Synchronized保证线程安全,每次插入数据时判断在当前数组下标是否是第一次插入,是就通过CAS方式插入,然后判断f.hash是否=-1,是的话就说明其他线程正在进行扩容,当前线程也会参加扩容;删除方法用了synchronized修饰,保证并发下移除元素安全
8、HashTable与HashMap的区别
(1)HashTable的每个方法都用synchronized修饰,因此是线程安全的,但同时读写效率很低
(2)HashTable的key不允许为null
(3)HashTable只对key进行一次hash,HashMap进行了两次Hash
(4)HashTable低层使用的数组加链表
9、ArrayList和LinkedList的区别
ArrayList的低层使用动态数组,默认容量为10,当元素数量到达容量时,生成一个新的数组,大小为前一次的1.5倍,然后将原来的数组copy过来;

因为数组有索引,所以ArrayList查找数据更快,但是添加数据效率更低

LinekdList的低层使用链表,在内存中是离散的,但是没有扩容机制;LinkedList在查找数据时需要从头遍历,所以查找慢,但是添加数据效率更高
10、如何保证ArrayList的线程安全
(1)使用collections.synchronizedList()方法为ArrayList加锁
(2)使用Vector,Vector低层与Arraylist相同,但是每个方法都有synchronized修饰,速度很慢
(3)使用juc下的CopyOnWriteArrayList,该类实现了读操作不加锁,写操作时为list创建一个副本,期间其他线程读取的都是list,写操作都在副本中进行,写入完成后,再将指针指向副本
11、String、StringBuffer、StringBuilder的区别
String由char[]数组构成,使用了final修饰,对String进行改变时每次都会新生成一个String对象,然后把指针指向新的引用对象。

StringBuffer可变且线程安全;

StringBuilder不可变并且线程不安全。

操作少量字符数据用String;单线程操作大量数据用StringBuilder;多线程操作大量数据用StringBuffer

二、Java多线程篇

1、进程和线程的区别
进程:系统运行的基本单位,包含多个线程

线程:独立运行的最小单位,是进程的实体,多个线程共享同一进程内的系统资源
2、什么是线程上下文切换
当一个线程被剥夺cpu使用权时,切换到另外一个线程执行
3、什么时死锁
死锁指多个线程在执行过程中,因争夺资源造成的一种互相等待的僵局
4、死锁的必要条件
互斥条件:同一资源同时只能由一个线程读取

不可抢占条件:不能强行剥夺线程占有的资源

请求和保持条件:请求其他组资源的同时对自己手中的资源保持不放

循环等待条件:在互相等待资源中,形成一个闭环

想要预防死锁,只需要破环其中一个条件即可,银行家算法可以预防死锁
5、Synchronized和lock的区别
(1)synchronized是关键字,lock是一个类

(2)synchronized在发生异常时会自动释放锁,lock需要手动释放锁

(3)synchronized是可重入锁、非公平锁、不可中断锁、lock是可重入锁、可中断锁,可以是公平锁
6、sleep()和wait()的区别
(1)wait()是Object方法,sleep是Thread类的方法

(2)wait()会释放锁,sleep不会释放锁

(3)wait()要在同步方法或者同步代码块中执行,sleep()没有限制

(4)wait()要调用notify()或notifyall()唤醒,sleep自动唤醒
7、yield()和join()的区别
yield()调用后线程进入就绪状态

A线程中调用B线程的join(),则B执行完毕A进入阻塞状态
8、线程池七大参数
核心线程数:线程池中的基本线程数量

最大线程数:当阻塞队列满了之后,逐一启动

最大线程的存活时间:当阻塞队列的任务执行完毕后,最大线程的回收时间

阻塞队列:当核心线程满后,后面来的任务都进入阻塞队列

线程工厂:用于生产线程

任务拒绝策略:阻塞队列满后,拒绝任务,有四种策略(1)抛异常(2)丢弃任务不抛异常(3)打回任务(4)尝试与最老的线程竞争
9、Java内存模型
JMM(Java内存模型)屏蔽了各种硬件和操作系统的内存访问差异,实现让Java程序在各平台下都能达到一致的内存访问效果,它定义了JVM如何将程序中的变量在主存中读取

具体定义为:所有变量都存在主存中,主存是线程共享区域;每个线程都有自己独有的工作内存,线程想要操作变量必须从主存中copy到自己的工作区,每个线程的工作内存是互相隔离的

由于主存与工作内存之间有读写延迟,且读写不是原子性操作,所以会有线程安全问题
10、保证并发安全的三大特性
原子性:一次或多次操作在执行期间不被其他线程影响

可见性:当一个线程在工作内存修改了变量,其他线程能立刻知道

有序性:JVM对指令的优化会让指令执行顺序改变,有序性是禁止指令重排

11、volatile(翻译:挥发性的)
volatie详解
保证变量的可见性和有序性,不保证原子性。使用了volatile修饰变量后,在变量修改后会立即同步到主存中,每次用这个变量都会从主存刷新。

单例模式双重校验锁变量为什么使用volatile修饰?禁止JVM指令重排序,new Object()分为三个步骤:申请内存空间,将内存空间引用赋值给变量,变量初始化。如果不禁止重排序,有可能得到一个未经初始化的变量。
12、线程使用方式
(1)继承Thread类

(2)实现Runnable接口

(3)实现Callable接口:但有返回值

13、ThreadLocal(翻译:本地线程)原理
ThreadLocal详解及各名词解释
原理是为每个线程创建变量副本,不同线程之间不可见,保证线程安全。每个线程内部都维护了一个Map,key为threadLocal实例,value为要保存的副本。

但是使用ThreadLocal会存在内存泄漏问题,因为key为弱引用,而value为强引用,每次gc时key都会回收,而value不会回收。所以为了解决内存泄漏问题,可以在每次使用完后删除value或者使用static修饰ThreadLocal,可以随时获取value
14、什么是ABA锁
ABA详解
CAS锁可以保证原子性,思想是更新内存时会判断内存是否被修改过,如果没有就直接更新。如果被修改,就重新获取值,直到更新完成为止。这样的缺点是:
(1)只能支持一个变量的原子操作,不能保证整个代码块的原子操作

(2)CAS频繁失败导致cpu开销大

(3)ABS问题:线程1和线程2同时去修改一个变量,将值从A改为B,但线程1突然阻塞,此时线程2将A改为B,然后线程2又将B改成A,这个过程线程2是不知道的,这就是ABA问题,可以通过版本号或时间戳解决
15、Synchronized锁原理和优化
(T_T好难理解)
Synchronized是通过对象头的markword来表明监视器的,监视器本质是依赖操作系统的互斥锁实现的。操作系统实现线程切换要从用户态切换为核心态,成本很高,此时这种锁叫重量级锁,在JDK1.6以后引入了偏向锁、轻量级锁、重量级锁

偏向锁:当一段代码没有别的线程访问,此时线程去访问会直接偏向锁

轻量级锁:当锁是偏向锁时,有另外一个线程来访问,偏向锁会升级为轻量级锁,这个线程会通过自旋方式不断获取锁,不会阻塞,提高性能

重量级锁:轻量级锁自旋一段时间后线程还没有获取到锁,线程就会进入阻塞状态,该锁就会升级为重量级锁,重量级锁时,来竞争锁的所有线程都会阻塞,性能降低

注意,锁只能升级不能降低
16、JUC常用辅助类
CountDownLatch:设定一个数,当调用CountDown()时数量减一,当调用await()时判断计数器是否为0,不为0就阻塞,直到计数器为0

CycilcBarrier:设定一个数,当调用await()时判断计数器是否达到目标值,未达到就阻塞,直到计数器达到目标值

Semaphore:设定一个信号量,当调用acquire()时判断是否还有信号,有就信号量减一线程继续执行,没有就阻塞等待其他线程释放信号量,当调用release()时释放信号量,唤醒阻塞线程

17.如何根据 CPU 核心数设计线程池线程数量
IO 密集型:核心数*2

计算密集型: 核心数+1

为什么加 1?即使当计算密集型的线程偶尔由于缺失故障或者其他原因而暂停时,这个额外的线程也能确保 CPU 的时钟周期不会被浪费。

三、JVM篇

四、MySql篇

1、MyIAm和InnoDB的区别
InnoDB支持事务,MyIAm不支持

InnoDB支持外键,MyIAm不支持

InnoDB是聚簇索引,MyIAm是非聚簇索引

InnoDB支持行锁和表锁,MyIAm只支持表锁

InnoDB不支持全文索引,MyIAm支持

InnoDB支持自增和MVCC模式的读写,MyIAm不支持
2、MVCC是什么
MVCC是多版本并发控制,为每次事务生成一个新版本数据,每个事务都由自己的版本,从而不加锁就决绝读写冲突,这种读叫做快照读。只在读已提交和可重复读中生效。

实现原理由四个东西保证,他们是

undolog日志:记录了数据历史版本

readView:事务进行快照读时产生的视图,记录了当前系统中活跃的事务id,控制哪个历史版本对当前事务可见

隐藏字段DB_TRC_ID: 最近修改记录的事务ID

隐藏字段DB_Roll_PTR: 回滚指针,配合undolog指向数据的上一个版本
3、MySQL有哪些索引
主键索引:一张表只能有一个主键索引,主键索引列不能有空值和重复值

唯一索引:唯一索引不能有相同值,但允许为空

普通索引:允许出现重复值

组合索引:对多个字段建立一个联合索引,减少索引开销,遵循最左匹配原则

全文索引:myisam引擎支持,通过建立倒排索引提升检索效率,广泛用于搜索引擎

五、Spring系列

1、Bean的作用域
(1)Singleton:一个IOC容器只有一个
(2)Prototype:每次调用getBean()都会生成一个新的对象
(3)request:每个http请求都会创建一个自己的bean
(4)session:同一个session共享一个实例
(5)application:整个serverContext只有一个bean
(6)webSocket:一个websocket只有一个bean
2、Bean生命周期
实例化Instantiation – 属性赋值Populate --初始化Initialization – 销毁Destruction

在这四步的基础上,Spring提供了一些扩展点:

Bean自身的方法:包括了Bean自身调用的方法和通过配置文件中的init-method和destroy-method指定的方法

Bean级生命周期接口方法:包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口方法

容器级生命周期接口方法:包括了 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。

工厂后处理器接口方法: 包括了 AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer 等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值