「java工程师」常见面试题及其答案(持续更新)

「高级java工程师」常见面试题及其答案:

「高级java工程师」常见面试题及其答案(持续更新)_好人老李的博客-CSDN博客

目录

java基础

面向对象与面向过程的区别?

JRE、JDK、JVM的区别?

java的数据类型有哪些?

重写和重载的区别?

java创建对象有几种方式?

反射

什么是反射?有什么作用?

反射的优缺点?

==和equals()的区别?

final、finally、 finalize 的区别?

String

String类为什么设计成不可变?

String、StringBuffer和StringBuilder的区别?

异常

java常见的异常类型有哪些?有什么区别?

IO

BIO、NIO、AIO 有什么区别?

序列化和反序列化

什么是序列化和反序列化?

序列化的作用?

什么是serialVersionUID?

如何生成serialVersionUID?

如何实现序列化?

集合

ArrayList和LinkedList的区别?

HashMap 的工作原理?

HashMap的扩容机制?

ConcurrentHashMap工作原理?

HashMap和HashTable的区别?

多线程

进程和线程的区别?

线程有几种状态?

sleep() 和 wait() 有什么区别?

创建线程有哪几种方式?

如何停止一个正在运行的线程?

线程池的工作原理?

synchronized与ReentrantLock的区别?

什么是死锁?如何防止死锁?

什么是threadlocal?工作原理?

volatile的作用和原理?

JVM

JVM对锁进行了哪些优化?

JVM 是由哪几部分组成的?

谈谈类的加载过程?

类加载器有哪些?

什么是双亲委派模型?有没有办法打破?

java对象的内存结构?

什么是引用?java中引用有几种类型?

深拷贝和浅拷贝的区别?

gc有哪些类型?有什么区别?

常用的垃圾回收算法有哪些?

jvm中,有哪些垃圾收集器?

哪些对象可以作为GC时的根节点?

Spring

Spring、SpringMVC、SpringBoot的关系?

mysql

索引为什么会让查询变快?

MyISAM和innoDB的区别?

并发事务有哪些问题?

数据库的事务隔离?

redis

redis为什么快?

redis为什么是单线程?

redis 持久化有几种方式?

缓存常见问题及其解法?

消息队列

消息队列的作用?如何选型?

消息队列常见问题及其解法?

分布式

什么是CAP理论和BASE理论?

ZK的工作原理?使用场景?

dubbo的架构和工作原理?

网络通信

TCP三次握手和四次挥手的过程?

TCP是3次握手,但挥手为什么需要4次,而不是3次挥手?

安全

加密算法有哪些?

加密和签名,有什么区别?


java基础

面向对象与面向过程的区别?

面向过程(Procedure xx,简称POP)的思想是:

分析解决问题需要哪些步骤 → 每一个步骤使用函数实现 → 依次调用函数来解决问题

以「把大象搬进冰箱」这个经典问题为例,面向过程的解决思路:

  1. 解决问题分3步:打开冰箱 → 搬大象 → 关闭冰箱

  2. 设计对应的方法:openFridge()、moveElephant()、closeFridge()

  3. 依次调用

int main() { 
    openFridge(); 
    moveElephant(); 
    closeFridge(); 
}

面向对象(Object xx,简称OOP)的思路是:

分析问题由哪些对象组成 → 使用类实现每一个对象 → 调用对象的方法来解决问题

还是以「把大象搬进冰箱」为例:

  1. 这个问题有涉及2个对象,冰箱和大象

  2. 使用类实现冰箱和大象,冰箱要具备开门和关门的能力,大象要具备走路的能力

  3. 实例化冰箱和大象,调用对象的方法就可以解决问题

class Elephant{ 
    public static void walkInto(target){} 
} 
class Fridge{ 
    public static void open(){ } 
    public static void close(){ } 
} 
class APP{ 
    public static void main(String[] args){ 
        Fridge.open(); //冰箱开门 
        Elephant.walkInto(Fridge); //大象走进冰箱 
        Fridge.close(); //冰箱关门 
    } 
}

面向过程和面向对象的区别:

面向过程:

  • 优点:性能好,面向对象需要先对类进行实例化,再调用对象的方法,面向过程直接调用函数

  • 缺点:复用性差,扩展性差

面向对象:

  • 优点:面向对象有封装、继承、多态的特性,易复用易扩展

  • 缺点:性能相对差一些,一般来说java程序执行速度比C慢10倍

JRE、JDK、JVM的区别?

  • JDK:Java Development Kit,是一个工具包,用于开发和运行Java程序,包含了java开发工具和JRE。
  • JRE:Java Runtime Environment,提供了一个java程序的运行环境。
  • JVM:Java 虚拟机,负责执行 Java 程序。

总结:JDK包含JRE,JRE包含JVM。

java的数据类型有哪些?

java的数据类型有两种:

  1. 基本数据类型
  2. 引用数据类型

基本数据类型又包括四类8种:

  1. 整数型:byte 1字节 [-128~127],short 2字节,int 4字节,long 8字节
  2. 浮点型:float  4字节,double(默认) 8字节
  3. 字符型:char,2字节,unicode编码值
  4. 布尔型:boolean,1字节,值只有true和false

重写和重载的区别?

  • 重载:overloading,发生在类内部,方法名相同,参数不同。
  • 重写:overriding,是子类对父类的方法进行重写, 返回值和形参不能改变。
  • 重写和重载是java多态性的不同表现形式

java创建对象有几种方式?

1. new

Person person = new Person(18);

2. Class.newInstance

Class person = Person.class;
Person person = null;
try {
    person = (Person) person.newInstance();
} catch (Exception e) {
    e.printStackTrace();
}

3. 反序列化(比较耗内存)

Person person = new Person("fsx", 18);
byte[] bytes = SerializationUtils.serialize(person);
Object deserPerson = SerializationUtils.deserialize(bytes);

4. clone()(对象必须实现Cloneable接口,并重写clone方法)

Person person1 = new Person(18);
Person person2 = person1.clone();

反射

什么是反射?有什么作用?

什么是反射:反射是java的一种机制,可以在运行态,获取任意一个类的所有属性和方法,可以用来创建对象、调用方法、对属性进行赋值。

Class<?> clz = Class.forName("xxx.User");
Object object = clz.newInstance();

反射的优缺点?

反射的优点:能够在运行时动态获取类的实例,提高了程序的灵活性

反射的缺点:反射机制中包括了一些动态类型,JVM无法对反射代码进行优化,因此性能较差,对性能要求高的程序尽量少用反射。

==和equals()的区别?

==:引用是否相同,是不是指向同一个内存空间

equals():值是否相同,所指向的内存空间的值是不是相同

String a = new String("123");
String b = new String("123");
a == b //false
a.equals(b) //true

final、finally、 finalize 的区别?

  • final:java的1个关键字,代表最终。如果一个类被声明为final,它不能被继承;如果变量声明为final,给定初始值后,不可修改;如果方法声明为final,不能被重载。
  • finally:java的一种异常处理机制,finally代码总会执行。
  • finalize:java中的一个方法名,在Object类中定义,因此所的类都继承了它,finalize()方法在垃圾收集器删除对象之前对会被调用。

String

String类为什么设计成不可变?

  • 字符串常量池:字符串常量池(String pool) 是Java堆内存中的一个特殊存储区域,当创建一个String对象时,如果此字符串值已存在于常量池,则不会创建一个新的对象,而是引用已经存在的对象,达到复用的效果。String类如果可变,常量池就不支持了。
  • 效率:String对象经常会被比较,如果不可变,String对象的哈希码就可以被缓存,不必每次都计算哈希码,提升性能。

  • 安全:String经常用做重要参数使用,例如URL、文件路径等,如果可变,会有安全隐患。

String、StringBuffer和StringBuilder的区别?

  • String是一个字符串常量,不可改变;StringBuffer和StringBuilder是字符串变量,可以改变,但StringBuffer是线程安全的,StringBuilder是非线程安全的。
  • 如何选择?如果修改少,使用String;如果在多线程下经常修改,使用SreingBuffer;如果是单线程下经常修改,使用StringBuilder。

异常

java常见的异常类型有哪些?有什么区别?

java异常的顶层类是Throwable,他的子类是:Error和Exception。

Error:运行时环境错误,如:内存溢出、系统崩溃等,程序无法恢复。

Exception:可捕获且可恢复的异常,Exception又分为两类:

  • CheckedException(可检查异常/编译时异常):可检查异常需要在源代码里显式地使用try catch捕获,否则编译不过。如IOException、SQLException等。
  • RuntimeException(不可检查异常/运行时异常):运行时异常是可能被程序员忽略的异常。如:ArrayIndexOutOfBoundsException(数组下标越界)、NullPointerException(空指针异常等。

IO

BIO、NIO、AIO 有什么区别?

先了解下1个IO请求的处理过程:

同步和异步的区别:同步和异步,是处理方处理IO请求的2种方式,同步是指IO处理线程会一直等待相关的IO数据就绪后再执行逻辑处理,异步是指IO处理线程不会一直等待相关的IO数据就绪,比如可以轮询查看相关IO数据是否已经准备OK。

阻塞和非阻塞的区别:阻塞和非阻塞,是调用方的2种IO请求方式,阻塞是指调用方一直等待处理方的结果,非阻塞是调用方不会一直等待处理方的结果,可以先去执行其他任务,过一段时间再来查看结果是否返回。

BIO:Blocking IO,同步阻塞IO。调用方发起IO请求后,会一直阻塞等待结果返回,同时处理方会一直等到IO数据就绪后,再进入处理。优点:一请求一应答的方式,逻辑简单,易实现。缺点:大量等待,性能很差。

NIO:Non-Blocking IO,同步非阻塞IO。调用方发起IO请求后,会一直阻塞等待结果返回。IO处理线程不会原地等待IO数据,可以先做其他事情,定时轮询检查IO数据是否就绪。

AIO:异步非阻塞IO。调用方发起IO请求后,不会等待结果,先处理其他事情,处理方执行完操作后利用系统函数告知调用方结果。IO处理线程不会原地等待IO数据,可以先做其他事情,定时轮询检查IO数据是否就绪。

序列化和反序列化

什么是序列化和反序列化?

序列化是指将对象写入IO流,反序列化是指从IO流中恢复对象。

序列化的作用?

  1. 远程传输对象
  2. 持久化保存对象

什么是serialVersionUID?

  • serialVersionUID是序列化的版本号, 序列化时,其值与数据一起存储;反序列化时,将检查序列化数据是否与当前类版本匹配。
  • 实现Serializable接口的类都有一个表示序列化版本标识符的静态变量,缺少serialVersionUID时,IDE会发出警告。

如何生成serialVersionUID?

  1. 使用默认值:private static final long serialVersionUID = 1L;
  2. 自动生成: private static final long serialVersionUID = 4603642343377807741L;
  3. 看诉求:如果希望类的不同版本序列化时兼容,需确保类的不同版本具有相同的serialVersionUID;如果不希望类的不同版本序列化时兼容,需确保类的不同版本具有不同的serialVersionUID。

如何实现序列化?

注意:JavaBean实体类必须实现Serializable接口,否则无法序列化。

public class User implements Serializable {   
    private static final long serialVersionUID = -7890663945232864573L;   
    private String userName;   
    public String getUserName() {     
        return userName;   
    }   
    public void setUserName(String userName) {     
        this.userName = userName;   
    }
    @Override   
    public String toString() {     
        return "User [userName=" + userName + ", passWord=" + passWord + "]";   
    } 
}

方式1:IO流序列化

    Java原生序列化方法是指通过 InputStream 和 OutputStream 之间的转化进行序列化和反序列化。

User u = new User(); 
u.setUserName("张三"); 
// 序列化 
ByteArrayOutputStream out = new ByteArrayOutputStream(); 
ObjectOutputStream obj = new ObjectOutputStream(out); 
obj.writeObject(u); 
// 反序列化 
ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(
    new java.io.ByteArrayInputStream(out.toByteArray()))); 
User user = (User) ois.readObject();

方式2:jackson序列化

大多数公司都将json作为服务器端返回的数据格式,Json序列化一般会使用jackson包。

import com.fasterxml.jackson.databind.ObjectMapper; 
User u = new User(); 
u.setUserName("张三"); 
// 序列化 
ObjectMapper mapper = new ObjectMapper(); 
byte[] writeValueAsBytes = null; 
writeValueAsBytes = mapper.writeValueAsBytes(u); 
// 反序列化 
User user = mapper.readValue(writeValueAsBytes, User.class);

方式3:FastJson/Gson

fastjson是由阿里巴巴开源的Json解析器和生成器,不过安全漏洞多,不建议使用,推荐使用Google的Gson。

集合

ArrayList和LinkedList的区别?

  1. 都是对List接口的实现,但一个底层是Array(动态数组),一个是Link(链表)
  2. 随机访问时(get和set操作),ArrayList比LinkedList的效率更高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找。
  3. 对数据进行增加和删除的操作时(add和remove操作),LinkedList比ArrayList的效率更高,因为ArrayList是数组,所以在其中进行增删操作时,会对操作点之后所有数据的下标索引造成影响,需要进行数据的移动。

HashMap 的工作原理?

        HashMap是Map接口的一种实现,用于存储K-V数据结构的元素。

HashMap的数据结构:

  • JDK7,HashMap的内部数据结构是数组+链表:

  • JDK8开始,当链表长度 > 8时会转化为红黑树,当红黑树元素个数 ≤ 6时会转化为链表。

put元素的原理:

  1. 计算K的hash值:hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)

  2. 计算K的数组位置:index = hash & (length - 1)

  3. 如果有相同K,则覆盖V

  4. 如果没有相同K,JDK7采用头插法(刚添加的元素被访问的概率大),但会引入循环引用问题,导致CPU高,JDK8开始采用尾插法,避免了这个问题。

  5. 如果元素个数超过阈值,进行扩容或数据结构变更(链表 → 红黑树)的操作。

get元素的原理:

  1. 计算K的hash值

  2. 计算K的数组index值

  3. 遍历寻找元素

HashMap的扩容机制?

什么时候扩容?

        当元素数量超过阈值时扩容,阈值 = 数组容量 * 加载因子,数组容量默认16,加载因子默认0.75,所以默认阈值12。

为什么容量必须是2的幂?

        计算K的数组位置公式:index = h & (length-1),由于2的幂次方-1都是1,这样运算时就可以充分利用到数据的高低位特点,减少hash冲突的概率,提升存取效率。

扩容的原理:

  1. 创建新数组,容量翻倍

  2. 旧数组元素迁移到新数组

ConcurrentHashMap工作原理?

        HashMap线程不安全,多线程环境可以使用Collections.synchronizedMap、HashTable实现线程安全,但性能不佳。ConurrentHashMap比较适合高并发场景使用。

ConcurrentHashMap JDK7实现原理:

数据结构:

  • ConcurrentHashMap由一个Segment数组构成(默认长度16&#x

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值