2023年春招必备Java八股文(通俗易懂)

时间:2023-04-28 16:18 来源:哔哩哔哩

一、Java基础篇

1.接口和抽象类的区别


(资料图)

2.重载和重写的区别

3.==和equals的区别

4.异常处理机制

5.HashMap原理

6.想要线程安全的HashMap怎么办?

7.ConcurrentHashMap原如何保证的线程安全?

8.HashTable与HashMap的区别

9.ArrayList和LinkedList的区别

10.如何保证ArrayList的线程安全?

11.String、StringBuffer、StringBuilder的区别

12.hashCode和equals

13.面向对象和面向过程的区别

4.深拷贝和浅拷贝

15.多态的作用

16.什么是反射?

17.Java创建对象得五种方式?

二.Java多线程篇

1.进程和线程的区别,进程间如何通信

2. 什么是线程上下文切换

3.什么是死锁

4.死锁的必要条件

5.Synchrpnized和lock的区别

6.什么是AQS锁?

8.有哪些常见的AQS锁

10.yield()和join()区别

11.线程池七大参数

12.Java内存模型 

13.保证并发安全的三大特性?

14.volatile

15.线程使用方式

16.ThreadLocal原理

17.什么是CAS锁

18.Synchronized锁原理和优化

19.如何根据 CPU 核心数设计线程池线程数量

一、Java基础篇

1.接口和抽象类的区别

相似点:

(1)接口和抽象类都不能被实例化

(2)实现接口或继承抽象类的普通子类都必须实现这些抽象方法

不同点:

(1)抽象类可以包含普通方法和代码块,接口里只能包含抽象方法,静态方法和默认方法,

(2)抽象类可以有构造方法,而接口没有

(3)抽象类中的成员变量可以是各种类型的,接口的成员变量只能是 public static final 类型的,并且必须赋值

2.重载和重写的区别

重载发生在同一个类中,方法名相同、参数列表、返回类型、权限修饰符可以不同

重写发生在子类中,方法名相、参数列表、返回类型都相同,权限修饰符要大于父类方法,声明异常范围要小于父类方法,但是final和private修饰的方法不可重写

3.==和equals的区别

==比较基本类型,比较的是值,==比较引用类型,比较的是内存地址

equlas是Object类的方法,本质上与==一样,但是有些类重写了equals方法,比如String的equals被重写后,比较的是字符值,另外重写了equlas后,也必须重写hashcode()方法

4.异常处理机制

(1)使用try、catch、finaly捕获异常,finaly中的代码一定会执行,捕获异常后程序会继续执行

(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()方法

7.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的区别

ArratList的底层使用动态数组,默认容量为10,当元素数量到达容量时,生成一个新的数组,大小为前一次的1.5倍,然后将原来的数组copy过来;因为数组在内存中是连续的地址,所以ArrayList查找数据更快,由于扩容机制添加数据效率更低

LinkedList的底层使用链表,在内存中是离散的,没有扩容机制;LinkedList在查找数据时需要从头遍历,所以查找慢,但是添加数据效率更高

10.如何保证ArrayList的线程安全?

(1)使用collentions.synchronizedList()方法为ArrayList加锁

(2)使用Vector,Vector底层与Arraylist相同,但是每个方法都由synchronized修饰,速度很慢

(3)使用juc下的CopyOnWriterArrayList,该类实现了读操作不加锁,写操作时为list创建一个副本,期间其它线程读取的都是原本list,写操作都在副本中进行,写入完成后,再将指针指向副本。

11.String、StringBuffer、StringBuilder的区别

String 由 char[] 数组构成,使用了 final 修饰,对 String 进行改变时每次都会新生成一个 String 对象,然后把指针指向新的引用对象。

StringBuffer可变并且线程安全

StringBuiler可变但线程不安全。

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

12.hashCode和equals

hashCode()和equals()都是Obkect类的方法,hashCode()默认是通过地址来计算hash码,但是可能被重写过用内容来计算hash码,equals()默认通过地址判断两个对象是否相等,但是可能被重写用内容来比较两个对象

所以两个对象相等,他们的hashCode和equals一定相等,但是hashCode相等的两个对象未必相等

如果重写equals()必须重写hashCode(),比如在HashMap中,key如果是String类型,String如果只重写了equals()而没有重写hashcode()的话,则两个equals()比较为true的key,因为hashcode不同导致两个key没有出现在一个索引上,就会出现map中存在两个相同的key

13.面向对象和面向过程的区别

面向对象有封装、继承、多态性的特性,所以相比面向过程易维护、易复用、易扩展,但是因为类调用时要实例化,所以开销大性能比面向过程低

4.深拷贝和浅拷贝

浅拷贝:浅拷贝只复制某个对象的引用,而不复制对象本身,新旧对象还是共享同一块内存

深拷贝:深拷贝会创造一个一摸一样的对象,新对象和原对象不共享内存,修改新对象不会改变原对对象。

15.多态的作用

多态的实现要有继承、重写,父类引用指向子类对象。它的好处是可以消除类型之间的耦合关系,增加类的可扩充性和灵活性。

16.什么是反射?

反射是通过获取类的class对象,然后动态的获取到这个类的内部结构,动态的去操作类的属性和方法。

应用场景有:要操作权限不够的类属性和方法时、实现自定义注解时、动态加载第三方jar包时、按需加载类,节省编译和初始化时间;

获取class对象的方法有:class.forName(类路径),类.class(),对象的getClass()

17.Java创建对象得五种方式?

(1)new关键字   (2)Class.newInstance  (3)Constructor.newInstance

(4)Clone方法   (5)反序列化

关键词:
x 广告
x 广告