Java高频面试题(2025最新版)

364 阅读18分钟

Java基础

1、JDK 、JRE、JVM 有什么区别?

JDK(Java Development Kit),[Java开发工具包]
JRE(Java Runtime Environment),Java运行时环境
JVM(Java Virtual Machine),运行 Java 字节码的虚拟机
JDK中包含JRE,JDK中有一个名为jre的目录,里面包含两个文件夹bin和lib,bin就是JVM,lib就是JVM工作所需要的类库。

2、== 和 equals 的区别是什么?

1、对于基本类型,== 比较的是值;
2、对于引用类型,== 比较的对象的内存地址;
3、equals不能用于基本类型的比较;
4、如果没有重写equals方法,equals就相当于==;
5、如果重写了equals方法,equals比较的是对象的属性是否相等;

3、final 在 java 中有什么作用?

(1)用来修饰一个引用
如果引用为基本数据类型,则该引用为常量,该值无法修改;
如果引用为引用数据类型,比如对象、数组,则该对象、数组本身可以修改,但指向该对象或数组的地址的引用不能修改。
如果引用时类的成员变量,则必须当场赋值,否则编译会报错。
(2)用来修饰一个方法
当使用final修饰方法时,这个方法将成为最终方法,无法被子类重写。但是,该方法仍然可以被继承。
(3)用来修饰类
当用final修改类时,该类成为最终类,无法被继承。比如常用的String类就是最终类。

这份小册是从基础到高级涵盖了足足30个技术栈的,包含了JAVA基础,JAVA集合,JAVA并发,Spring,微服务,Netty,计算机网络,MQ,Zookeeper,Redis,MySQL,数据结构与算法以及设计模式等等,足足200余页,由于掘金篇幅限制我在这里就只展示部分内容了,扫一扫免费获取

image.png

4、java 中的 Math.round(-11.3) 等于多少?

-11
Math提供了三个与取整有关的方法:ceil、floor、round
(1)ceil:向上取整;
Math.ceil(11.3) = 12;
Math.ceil(-11.3) = -11;
(2)floor:向下取整;
Math.floor(11.3) = 11;
Math.floor(-11.3) = -12;
(3)round:四舍五入;加0.5然后向下取整。
Math.round(11.3) = 11;
Math.round(11.8) = 12;
Math.round(-11.3) = -11;
Math.round(-11.8) = -12;

5、String str="xyz"与 String str=new String(“xyz”)一样吗?

两个语句都会先去字符串常量池中检查是否已经存在 “xyz”,如果有则直接使用,如果没有则会在常量池中创建 “xyz” 对象。
另外,String s = new String(“xyz”) 还会通过 new String() 在堆里创建一个内容与 “xyz” 相同的对象实例。
所以前者其实理解为被后者的所包含。

6、new String(“a”) + new String(“b”) 会创建几个对象?

如果字符串常量池中没有“a”和“b”,就是6个,否则就是4个
对象1:new StringBuilder()
对象2:new String(“a”)
对象3:常量池中的"a"
对象4:new String(“b”)
对象5:常量池中的"b"
深入剖析:StringBuilder中的toString():
对象6:new String(“ab”)
强调一下,toString()的调用,在字符串常量池中,没有生成"ab"
字符串常量池: JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。

7、如何将字符串反转?

将对象封装到stringBuilder中,调用reverse方法反转。

8、String 类的常用方法都有那些?

(1)常见String类的获取功能

length:获取字符串长度;
charAt(int index):获取指定索引位置的字符;
indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引;
substring(int start):从指定位置开始截取字符串,默认到末尾;
substring(int start,int end):从指定位置开始到指定位置结束截取字符串;

(2)常见String类的判断功能

equals(Object obj): 比较字符串的内容是否相同,区分大小写;
contains(String str): 判断字符串中是否包含传递进来的字符串;
startsWith(String str): 判断字符串是否以传递进来的字符串开头;
endsWith(String str): 判断字符串是否以传递进来的字符串结尾;
isEmpty(): 判断字符串的内容是否为空串"";

(3)常见String类的转换功能

byte[] getBytes(): 把字符串转换为字节数组;
char[] toCharArray(): 把字符串转换为字符数组;
String valueOf(char[] chs): 把字符数组转成字符串。valueOf可以将任意类型转为字符串;
toLowerCase(): 把字符串转成小写;
toUpperCase(): 把字符串转成大写;
concat(String str): 把字符串拼接;

(4)常见String类的其他常用功能

replace(char old,char new) 将指定字符进行互换
replace(String old,String new) 将指定字符串进行互换
trim() 去除两端空格
int compareTo(String str) 会对照ASCII 码表 从第一个字母进行减法运算 返回的就是这个减法的结果,如果前面几个字母一样会根据两个字符串的长度进行减法运算返回的就是这个减法的结果,如果连个字符串一摸一样 返回的就是0。

9、String、StringBuffer和StringBuilder区别?

String:字符串对象是不可变对象,虽然可以共享常量对象,但是对于频繁字符串的修改和拼接操作,效率极低
后面两者都是可变字符串对象
StringBuffer:线程安全的(因为它的方法有synchronized修饰)效率低
StringBuilder:线程不安全的 性能高
小结:
(1)如果要操作少量的数据用 String;
(2)多线程操作字符串缓冲区下操作大量数据用 StringBuffer;
(3)单线程操作字符串缓冲区下操作大量数据用 StringBuilder。
String不可变的真正原因
1、字符串的本质是char数组(jdk9以后是byte[]),被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法。
2、String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变。

10、 字符串拼接问题

(1)常量+常量:结果是常量池(常量优化,因为编译期间就可以确定结果)
(2)常量与变量 或 变量与变量:结果是堆
(3)拼接后调用intern方法:结果在常量池

String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2;
String str5 = "string";
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false

12345678

11、什么是自动拆装箱? int和Integer有什么区别?以及以下程序运行结果。

基本数据类型,如int,float,double,boolean,char,byte,不具备对象的特征,不能调用方法。
装箱:将基本类型转换成包装类对象
拆箱:将包装类对象转换成基本类型的值
java为什么要引入自动装箱和拆箱的功能?主要是用于java集合中,List list=new ArrayList();
list集合如果要放整数的话,只能放对象,不能放基本类型,因此需要将整数自动装箱成对象。
实现原理:javac编译器的语法糖,底层是通过Integer.valueOf()和Integer.intValue()方法实现。
区别:
(1)Integer是int的包装类,int则是java的一种基本数据类型
(2)Integer变量必须实例化后才能使用,而int变量不需要
(3)Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
(4)Integer的默认值是null,int的默认值是0

包装类型的缓存机制

Java 基本数据类型的包装类型的大部分都用到了缓存机制来提升性能。
Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据,Character 创建了数值在 [0,127] 范围的缓存数据,Boolean 直接返回 True or False。
如果超出对应范围仍然会去创建新的对象,缓存的范围区间的大小只是在性能和资源之间的权衡。
两种浮点数类型的包装类 Float,Double 并没有实现缓存机制。

public class Test01 {  
	public static void main(String[] args){  
		Integer a = 127;  
		Integer b = 127;  
		Integer c = 128;  
		Integer d = 128;  
		System.out.println(a==b); //true  
		System.out.println(c==d); //false 
		
		Float i11 = 333f;
		Float i22 = 333f;
		System.out.println(i11 == i22);//false
		
		Double i3 = 1.2;
		Double i4 = 1.2;
		System.out.println(i3 == i4);//false
	}  
} 

123456789101112131415161718

建议:所有整型包装类对象之间值的比较,建议使用 equals 方法比较。> >

这份小册是从基础到高级涵盖了足足30个技术栈的,包含了JAVA基础,JAVA集合,JAVA并发,Spring,微服务,Netty,计算机网络,MQ,Zookeeper,Redis,MySQL,数据结构与算法以及设计模式等等,足足200余页,由于掘金篇幅限制我在这里就只展示部分内容了,扫一扫免费获取

image.png

12、类和对象的关系

类是对同一类事物的描述,是抽象的
对象是一类事物的实现,是具体的
类是模板,对象是类的实例

13、怎么理解面向对象?

继承:描述的是事物之间的所属关系,is-a,子类继承父类的特征和行为,复用性 扩展性
封装:内部属性私有化,对外提供公共的访问方式,高内聚,低耦合
多态:同一个行为有不同的表现形式,多态存在3个条件:①继承②重写③父类引用指向子类实例 如List list = new ArrayList();

14、接口与抽象类的区别?

  1、成员变量
     	抽象类:既可以是常量也可以是变量
     	接口:一定是常量
  2、构造
      	抽象类:有构造
      	接口:没有构造
  3、成员方法
    	抽象类:既可以是普通方法,也可以是抽象方法
    	接口:JDK1.8之前,必须是抽象方法(JDK8之后出现了默认方法和静态方法,JDK9出现了私有方法)
  4、设计理念
      	抽象类:作为一个继承体系顶层,将共性行为和属性被继承下去,体现is-a的关系 单继承
      	接口:作为一个功能进行扩展 多实现(子类可以实现多个接口)

123456789101112

15、重载与重写有什么区别?

1、重载发生在本类,重写发生在父类与子类之间;
2、重载的方法名必须相同,重写的方法名相同且返回值类型必须相同;
3、重载的参数列表不同,重写的参数列表必须相同。
4、重写的访问权限不能比父类中被重写的方法的访问权限更低。
5、构造方法不能被重写

16、为什么要使用克隆?如何实现对象克隆?深拷贝和浅拷贝区别是什么?

(1)为什么要使用克隆?
想对一个对象进行复制,又想保留原有的对象进行接下来的操作,这个时候就需要克隆了。
(2)如何实现对象克隆?
1、实现Cloneable接口,重写clone方法;
2、实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深克隆。
BeanUtils,apache和Spring都提供了bean工具,只是这都是浅克隆。
(3)深拷贝和浅拷贝区别是什么?
浅拷贝:浅拷贝会在堆上创建一个新的对象(区别于引用拷贝的一点),不过,如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。
深拷贝:深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。

17、java 中 IO 流分为几种?

所谓的IO就是实现数据从磁盘的读取和写入。
实际上,除了磁盘以外,内存、网络都可以作为 I/O 流的数据来源和目的地。
在 Java 里面,提供了字符流和字节流两种方式来实现数据流的操作。
Java 里面提供了 Socket的方式来实现数据的网络传输。

在这里插入图片描述

18、 常见的IO模型:BIO、NIO、AIO

BIO

定义:同步阻塞IO,传统的IO模型,实现数据从磁盘中的读取以及写入。
特点:简单使用方便,但并发处理能力低。

NIO

定义:同步非阻塞 IO,是传统 IO 的升级,它是支持面向缓冲的,基于通道的 I/O 操作方法。了
特点:多路复用,减少CPU的小号,适用于高并发。

AIO

定义:异步非阻塞IO,是 NIO 的升级,也叫 NIO2,是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
特点:异步非阻塞

19、什么是 java 序列化?怎么实现序列化

序列化:把内存中的java对象转换为二进制字节流,用来实现存储或传输
反序列化:将从文件或者网络上获取到的对象的字节流转化为对象
序 列 化 的 实 现 :
只有实现了Serializable和Externalizeble的接口的类才能实现序列化。
Java.IO.ObjectOutputStream代表对象输出流。writeObject(Object obj)方法可对参数指定的obj对象进行序列化。
Java.IO.ObjectInputStream代表对象输入流,它的readObject()方法可以反序列化。
如果类中每个成员变量不想被序列化,可以用transient关键字修饰。

20、final、finally、finalize的区别?

final:修饰符(关键字)有三种用法:修饰类、变量和方法。修饰类时,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词。修饰变量时,该变量使用中不被改变,必须在声明时给定初值,在引用中只能读取不可修改,即为常量。修饰方法时,也同样只能使用,不能在子类中被重写。
finally:通常放在try…catch的后面构造最终执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。
finalize:Object类中定义的方法,Java中允许使用finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize() 方法可以整理系统资源或者执行其他清理工作。

21、Object中有哪些方法?

1)protected Object clone()--->创建并返回此对象的一个副本。 
(2)boolean equals(Object obj)--->指示某个其他对象是否与此对象“相等”。 
(3)protected void finalize()--->当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。 
(4)Class<? extendsObject> getClass()--->返回一个对象的运行时类。 
(5)int hashCode()--->返回该对象的哈希码值。 
(6)void notify()--->唤醒在此对象监视器上等待的单个线程。 
(7)void notifyAll()--->唤醒在此对象监视器上等待的所有线程。 
(8)String toString()--->返回该对象的字符串表示。 
(9)void wait()--->导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。 
	void wait(long timeout)--->导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll()方法,或者超过指定的时间量。 
	void wait(long timeout, int nanos)--->导致当前的线程等待,直到其他线程调用此对象的 notify()

1234567891011

22、异常相关

在 Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 Throwable 类。Throwable 类有两个重要的子类:
Exception :程序本身可以处理的异常,可以通过 catch 来进行捕获。Exception 又可以分为 Checked Exception (受检查异常,必须处理) 和 Unchecked Exception (非受检查异常,可以不处理)。
Error:Error 属于程序无法处理的错误 ,我们没办法通过 catch 来进行捕获。例如 Java 虚拟机运行错误(Virtual MachineError)、虚拟机内存不够错误(OutOfMemoryError)、类定义错误(NoClassDefFoundError)等 。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。

1、编译时异常:
IOException 输入输出流异常
FileNotFoundException 文件找不到的异常
ClassNotFoundException 类找不到异常
DataFormatException 数据格式化异常
NoSuchFieldException 没有匹配的属性异常
NoSuchMethodException 没有匹配的方法异常
SQLException 数据库操作异常
TimeoutException 执行超时异常
2、运行时异常(RuntimeException 及其子类都统称为非受检查异常)
ArrayIndexOutofBoundsException 数组越界异常
ClassCastException 类型转换异常
NullPointerException 空指针异常
IllegalAccessException 非法的参数异常
NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符。
ArithmeticException 算术异常

23、hashcode是什么?有什么作用?

hashcode是一种编码方式,在Java中,每个对象都会有一个hashcode,Java可以通过这个hashcode来识别一个对象。hashcode方法返回该对象的哈希码值,该方法为哈希表提供一些优点,就是通过这个哈希实现快速查找键对象
1、如果equals相等,hashcode一定相同
2、但hashcode相等,equals不一定相等(hash碰撞)
3、重写equals方法一定要重写hashcode方法(两个相等的对象hashcode一定相同)
HashCode的存在主要是为了查找的快捷性,HashCode是用来在散列存储结构中确定对象的存储地址的。如hashmap、hashtable

24、谈谈你对反射的理解?

(1)反射机制:
所谓的反射机制就是java语言在运行时拥有一项自观的能力。通过这种能力可以彻底的了解自身的情况为下一步的动作做准备。
Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method;
其中class代表的时类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略的看到一个类的各个组 成部分。
(2)Java反射的作用:
在Java运行时环境中,对于任意一个类,可以知道这个类有哪些属性和方法。对于任意一个对象,可以调用它的任意一个方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。
(3)Java 反射机制提供功能
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法

优点

  • 增加程序的灵活性,可以在运行的过程中动态对类进行修改和操作
  • 提高代码的复用率,比如动态代理,就是用到了反射来实现

缺点:

  • 破坏了代码本身的抽象性
  • 反射会涉及到动态类型的解析,所以 JVM 无法对这些代码进行优化,导致性能要比非反射调用更低。

25、linux常用命令

三个简单
ls:列出目录中的目录
cd:切换目录
mkdir :创建文件夹
cp:复制文件
mv:移动文件
cat、more:查看文件
三个复杂
ifconfig:查询当前网卡配置信息
tail -f xx.out 动态查看日志
netstat -anp | grep 端口号:查看端口号
top:查看内存
ps aux:查看进程
kill -9 进程号:杀死进程

26、docker常用命令

systemctr start/stop/restart docker 开启/停止/重启docker
docker images 查看所有镜像
docker pull 拉取镜像
docker rmi -f 删除镜像

docker ps 查看正在运行的容器
docker ps -a 查看所有的容器
docker run 启动容器
docker stop 停止容器
docker exec -it ‘容器名称或容器ID’ bash

docker logs -f 容器id/容器名称 实时查看日志
docker logs --tail=500 [容器id] 查看最后500行日志
docker logs -f --since “2022-06-22” [容器id或服务名称] 查看某个时间至今的日志