java基础面试

1.什么是对象?

类的运行实例,是堆当做的一块内存空间

2.java的特点:、

平台无关性(通过jvm(java虚拟机)将字节码文件翻译成特定平台下的机器码然后运行),面向对象,内存管理

4.数据类型
5.装箱和拆箱是什么?

自动装箱 是 Java 将基本数据类型(如 int)自动转换为对应的包装类对象(如 Integer)的过程;自动拆箱 则是将包装类对象(如 Integer)自动转换为对应的基本数据类型(如 int)的过程,本质是编译器自动帮我们调用了包装类的valueOf()(装箱)或xxxValue()(拆箱,如intValue())方法,简化了基本类型与包装类的转换代码。

结合代码中的变量:int a = 10, b = 10;Integer a1 = 10, b1 = 10; (自动装箱)Integer a2 = new Integer(10), b2 = new Integer(10); (手动新建对象)

  1. System.out.println(a == b); // T 分析:a 和 b 都是基本类型 int。 原因:对于基本类型,== 直接比较数值。10 == 10,结果为 true。

  2. System.out.println(a1 == b1); // T 分析:a1 和 b1 都是包装类 Integer,但采用了自动装箱(直接赋值)。 原因:Java 为了节省内存,给 Integer 提供了缓存池(范围是 -128 到 127)。 因为 10 在缓存范围内,a1 = 10 和 b1 = 10 并没有创建新对象,而是都指向了缓存池中同一个 Integer 对象。 == 比较引用地址,地址相同,结果为 true。

  3. System.out.println(a2 == b2); // F 分析:a2 和 b2 都是通过 new Integer(10) 手动创建的。 原因:只要你调用了 new 关键字,JVM 就会在堆内存中开辟两块新的、独立的空间。 a2 保存的是地址 A,b2 保存的是地址 B。 == 比较引用地址,地址不同,哪怕数值都是 10,结果也为 false。

  4. System.out.println(a1 == a); // T 分析:基本类型 vs 包装类型。 原因:这是发生了自动拆箱。当 == 两边一边是基本类型,一边是包装类型时,包装类型会自动拆箱变成基本类型。 实际比较的是 a1.intValue() (10) 和 a (10)。 退化为数值比较,结果为 true。

  5. System.out.println(a1.equals(a)); // true 分析:调用包装类的 equals() 方法,参数是基本类型。 原因:Integer 的 equals() 方法源码会先检查参数是否是 Integer 实例,如果不是(比如是 int),会先进行自动装箱,然后再比较数值。 实际比较的是 a1 的值 10 和 a 装箱后的值 10。 equals 比较内容,结果为 true。

  6. System.out.println(a1 == a2); // false 分析:缓存池对象 vs 新建对象。 原因:a1 指向缓存池中的对象(地址 X),a2 指向 new 出来的新对象(地址 Y)。 两者地址不同,== 比较地址,结果为 false。 注:如果用 a1.equals(a2),结果会是 true,因为数值都是 10。

  7. System.out.println(a == a2); // true 分析:同第 4 点。 原因:a2 自动拆箱为 int 类型的 10,与 a 的 10 比较数值,结果为 true。 三、 避坑指南(开发规范) 在实际开发(如你的 SSM/SpringBoot 项目)中,比较包装类(Integer、Long 等)时: 永远不要用 == 比较包装类对象,除非你明确想比较是否为同一个对象。 必须使用 equals() 方法来比较数值是否相等。 注意空指针:如果包装类可能为 null,直接调用 equals() 会报错。建议使用 Objects.equals(a1, a2),它能处理 null 值。

6.为什么用bigDecimal 不用double ?

double采用二进制浮点运算出现精度丢失,不能准确的表示一个小数

bigdecimal创建对象用字符串作为参数避免精度丢失

8.说一下 integer 的缓存

Java 的 Integer 类内部实现了一个静态缓存池,用于存储特定范围内的整数值对应的 Integer 对象。

默认情况下,这个范围是 - 128 至 127。当通过 Integer.valueOf (int) 方法创建一个在这个范围内的整数对象时,并不会每次都生成新的对象实例,而是复用缓存中的现有对象,会直接从内存中取出,不需要新建一个对象。

9.一、128 陷阱(Integer 缓存陷阱)简述

「128 陷阱」是 Java 中Integer包装类因缓存池机制导致的特殊现象:当用==比较自动装箱的Integer对象时,数值在-128~127范围内返回true,超出该范围(如 128、-129)则返回false,核心是==比较的是对象地址而非数值。 二、产生原因 缓存池设计:JVM 启动时会提前创建-128~127范围内的所有Integer对象,存入IntegerCache缓存池; 自动装箱逻辑:Integer i = 数值(自动装箱)底层调用Integer.valueOf(),数值在缓存范围则复用池内对象,超出则新建对象; == 的比较规则:==对引用类型比较内存地址,缓存内对象地址相同(返回true),新建对象地址不同(返回false)。 三、解决方法 核心方案:比较Integer数值时,永远用equals()(比较内容 / 数值),而非==(比较地址); 进阶方案:若对象可能为null,使用Objects.equals()(避免空指针异常);

面向对象

1.封装,继承,多态,

继承的本质是代码的复用子类继承父类的代码进行服用,封装指将对象的属性和行为结合在一起,对外隐藏对象的内部细节是的对象更加独立

多态:多态体现在方法重载方法重写,接口与实现,向上转型和向下转型

多态的关键前提(面试必提) 继承:必须有父类和子类的继承关系; 重写:子类必须重写父类的方法(核心,没有重写就没有多态); 父类引用指向子类对象:父类类型 变量名 = new 子类类型()(这是多态的语法体现)。

父类的引用指向子类对象向上转型

2.重载与重写有什么区别?

重载(Overloading)指的是在同一个类中,可以有多个同名方法,它们具有不同的参数列表(参数类型、参数个数或参数顺序不同),编译器根据调用时的参数类型来决定调用哪个方法。 重写(Overriding)指的是子类可以重新定义父类中的方法,方法名、参数列表和返回类型必须与父类中的方法一致,通过 @Override 注解来明确表示这是对父类方法的重写。 重载是指在同一个类中定义多个同名方法,而重写是指子类重新定义父类中的方法。

3.抽象类和接口的区别

继承限制不同:抽象类只能单继承,接口可多实现(这是最核心的区别,优先说);

方法和属性不同:抽象类可混有抽象方法和普通方法,能定义任意属性;接口默认是抽象方法和常量,JDK8 + 才支持 default/static 方法;

设计目的不同:抽象类是 "模板类",封装子类通用逻辑,体现继承关系;接口是 "行为契约",只约束要实现的行为,不关注实现细节。

接口方法的变量包含的变量做静态常量

4.java中final作用,

修饰的类不能被继承,final修饰的方法不能被重写,final修饰的变量不能对其重新赋值(固定的是地址)

5.类

是 "抽象的模板 / 规则",对象是 "符合规则的具体实例";类决定了对象的 "结构和能力",对象是类的 "实际应用"。

7.深拷贝和浅拷贝
  1. 浅拷贝和深拷贝的区别? 答:核心区别在引用类型成员变量的处理:浅拷贝仅复制引用地址,新旧对象共用引用数据;深拷贝递归复制所有引用类型的底层数据,新旧对象完全独立。

  2. Object 的 clone () 方法是深拷贝还是浅拷贝? 答:Object的clone()是浅拷贝,默认只拷贝对象本身和基本类型成员变量,引用类型仅拷贝地址。

  3. 实现深拷贝的方式有哪些? 答:① 引用类型成员变量也实现Cloneable,重写clone()方法;② 序列化(实现Serializable),通过字节流复制生成新对象(支持多层引用,更通用);③ 手动 new 所有引用类型成员变量,逐一赋值。

  4. 为什么要用到深拷贝? 答:当需要修改拷贝后的对象,又不想影响原对象时(比如电商订单复制、对象快照),必须用深拷贝;浅拷贝会导致修改拷贝对象时,原对象的引用数据被篡改,引发 bug。

实现深拷贝的三种方法是什么?

实现 Cloneable 接口并重写 clone() 方法;使用序列化和反序列化;手动递归复制

8.Java 中 static的作用是什么?

static 的核心是「归属于类,而非对象」:

  1. 静态变量 / 方法可通过类名直接调用,所有对象共享静态变量;

  2. 静态方法不能访问非静态成员,静态代码块在类加载时仅执行一次;

  3. 常用于定义工具方法、全局常量、类级别的初始化逻辑。

9.序列化

把内存中的Java 对象 转换成字节序列(二进制数据)的过程(比如把对象 "拆成" 可存储 / 传输的字节);

反序列化 :把字节序列重新转换成内存中 Java 对象的过程(把字节 "拼回" 原来的对象)。

继承serializable

· ObjectOutputStream:通过writeObject()方法做序列化操作。 ● ObjectlnputStrean:通过readObject()方法做反序列化操作。

10.泛型适用于多种数据类型执行相同的代码,不需要强制类型转换

11.java创建对象的方式:

(1)使用new关键字,(2)使用class类的newInstance(3)使用clone()(4)使用反序列化。(5)使用工厂模式

12.New出的对象什么时候回收?

简单来说,通过new创建的对象是由 JVM 的垃圾回收器 GC 自动管理的。我们无法指定某个对象立即被回收

GC 会在运行时定期检查,当一个对象不再被任何根引用可达时,比如局部变量出栈、静态变量不再引用它,GC 就会把它标记为垃圾。

具体什么时候回收,取决于 JVM 的内存压力和 GC 策略,比如堆内存不足时会触发 GC。另外,即使对象变成了垃圾,也只是被标记,真正释放内存还是 GC 决定。(现代 JVM 主要使用可达性分析算法判断对象是否存活)

对象不再可达 → GC 标记 → 适时回收,时间由 JVM 自动决定。

算法:

1,引用计数法:某个对象的引用计数为0时,表示改对象不在被引用,可以被回收。

2.可达性分析法

3.终结器

13.反射:

反射就是 Java 提供的一种机制 单说就是程序运行时能获取并操作任意类的所有信息。

获取 Class 对象;获取类的成员;突破访问限制;创建对象 / 调用方法。

实际中最核心的应用是框架,比如 Spring 的 IOC、MyBatis 的 Mapper,都是靠反射实现动态创建对象、调用方法。不过反射也有缺点,比如性能比直接调用差,还会破坏封装,所以一般框架会用,业务代码很少直接用。"

14.异常

异常处理:try-catch,throw用、手动抛出异常,throws生命可能抛出的异常类型

finally,是否发生异常都会执行的代码块。

抛出异常为什么不用throws:如果异常是未检查异常或者在方法内部被捕获和处理了,那么就不需要使用throws。

15。"Object 类的核心方法有 9 个,重点记这几个:

① equals 默认比地址,hashCode 和它配对重写;

② toString 默认返回类名 @哈希值,重写能打印对象属性;

③ getClass 是反射入口;

④ clone 做浅拷贝,需要实现 Cloneable;

⑤ wait/notify/notifyAll 是线程通信的方法,必须在同步代码块里用;

16.==与equals区别:

== 对基本类型比的值,对引用类型比的是地址;

==对于基本数据类型而言比较的是值是否相同,对用引用数据而言,比较的是引用地址是否相同 equals0方法不能在基本数据类型当中使用,Object类当中的equals0方法用的是==比较地址是否相同。 但是String类重写了equals0方法,先是比较地址是否相同,如果不相同则比较值是否相同

String 重写 equals () 必重写 hashCode ():

题 1:为什么重写 equals () 必须重写 hashCode ()? "核心是满足 Java 的通用约定:① equals 相等的对象,hashCode 必须相等;② 若不重写,会导致哈希集合(HashMap/HashSet)无法正确识别相同对象,比如两个内容相同的 String 会被当成不同元素存储,破坏集合的去重逻辑。" 题 2:String 的 equals () 和 hashCode () 的关系? "String 的 equals () 比较内容,hashCode () 基于内容计算哈希值:① 两个 String 的 equals () 相等 → hashCode 一定相等;② 两个 String 的 hashCode 相等 → equals () 不一定相等(哈希冲突,比如不同内容的字符串可能算出相同 hashCode)。" 题 3:hashCode () 相等,equals () 一定相等吗? "不一定!hashCode 相等只是说明两个对象在哈希集合中处于同一个桶位,可能是哈希冲突,必须通过 equals () 最终确认是否相同(比如 String 中'Aa'和'BB'的 hashCode 都是 2112,但 equals () 不相等)。" 四、面试口语化模板(直接背) "String 重写 equals () 是为了比内容,重写 hashCode () 是为了配合哈希集合:① 要是只重写 equals 不重写 hashCode,内容相同的 String 会有不同的 hashCode,放进 HashSet 会被当成两个对象;② Java 规定 equals 相等的对象 hashCode 必须相等,这是哈希集合能正常工作的基础,所以 String 两者都重写了,保证内容相同的 String,hashCode 也相同。"

17.题 1:注解的作用?

"注解主要有 3 个作用:① 语法检查(比如 @Override 避免重写方法名写错);② 简化配置(替代 XML,比如 Spring 的 @Controller);③ 生成代码(比如 Lombok 的 @Data 自动生成 get/set)。"

题 2:自定义注解的步骤?

"分 3 步:① 用 @interface 定义注解;② 加元注解(@Target 指定位置、@Retention 指定生命周期);③ 定义注解属性(支持基本类型、String、Class、数组等);④ 写解析逻辑(反射 / APT)。"

题 3:@Override 的作用?为什么是源码注解?

"@Override 告诉编译器这个方法是重写父类的,若方法名 / 参数写错,编译器会报错;它只在编译期有用,编译成字节码后就没用了,所以 @Retention 是 SOURCE。"

18."Socket 和 WebSocket (Netty)的核心区别,首先是本质不同:Socket 是操作系统提供的通信接口,是实现 TCP/UDP 通信的工具,能用于任何网络场景;而 WebSocket 是应用层协议,专门解决浏览器和服务器的实时通信问题,底层其实也是基于 Socket 实现的。

其次,使用场景和封装性不一样:Socket 需要自己处理数据格式、粘包拆包这些底层问题,通用性强;WebSocket 是为浏览器定制的,先 HTTP 握手再升级成长连接,封装得很好,不用管底层,只负责业务逻辑就行。

简单说,Socket 是'底层通用工具',WebSocket 是'浏览器场景的专用协议'。"

websocket和http一样都是应用层协议,他们也都是基于TCP的协议。ws协议的流程是:

  1. 首先经过TCP的三次握手

  2. 利用http协议升级为ws协议

  3. 后续双方通过websocket数据格式进行通信

18.java 中的代理模式
  • 定义:给目标对象提供一个代理对象,并且由代理对象控制对目标对象的引用

  • 目的

    :①:功能增强:通过代理业务对原有业务进行增强

    ②:控制访问:通过代理对象的方式间接的访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性

    静态代理和动态代理的本质区别是代理类的创建时机:

    静态代理的代理类是编译期手动编写的,每个目标类对应一个代理类,代码冗余但无反射、性能高;

    动态代理的代理类是运行时 JVM 通过反射动态生成的,一个代理逻辑能适配所有目标类,灵活但因为反射有轻微性能损耗。

    反射是动态代理的实现手段,而静态代理因为编译期就确定了代理关系,不需要反射。"

19.string
20.String、StringBuffer、StringBuilder的区别和联系
21."String 不可变主要有三点原因:
  1. 类被 final 修饰,不能被继承,避免子类破坏不可变性;

  2. 底层存储字符的 char 数组被 final 修饰,引用地址不能改变;

  3. 类没有提供任何修改数组内容的方法,所有修改操作都会返回新字符串对象,原对象保持不变。

    另外,不可变性还让 String 可以安全用于常量池、多线程场景,并且缓存哈希值,提升性能。"

22.BIO是同步阻塞io模型,nio是同步非阻塞io
23.tomcat执行流程

:二、分步拆解(面试直接背) 请求到达 Tomcat 端口客户端(浏览器)发送 HTTP 请求,到达 Tomcat 监听的端口(默认 8080),由 Tomcat 的连接器(Connector) 接收。✨ 关键:Connector 的核心是 Endpoint(端点),负责监听端口、接收 TCP 连接,再交给 Processor 解析成 HTTP 请求对象。 封装请求对象Connector 把 TCP 请求解析成标准的HttpServletRequest对象(封装请求行、请求头、请求体),同时创建HttpServletResponse对象用于封装响应。 交给 Engine 引擎Connector 将请求对象和响应对象交给 Tomcat 的顶级容器Engine(引擎),Engine 是整个 Servlet 容器的核心,负责管理所有虚拟主机。 匹配 Host 虚拟主机Engine 根据请求的域名(如localhost),匹配对应的Host(虚拟主机)(默认是localhost),如果没有匹配到,用默认 Host 处理。 匹配 Context 上下文(项目)Host 根据请求的 URL 路径(如/demo),匹配对应的Context(上下文,对应一个 Web 项目),比如/demo对应部署的 demo.war 项目。 匹配 ServletContext 根据 URL 路径(如/demo/user),通过Servlet 映射(web.xml/@WebServlet) 找到对应的 Servlet(或 SpringMVC 的 DispatcherServlet),如果没匹配到,返回 404。 Servlet 处理业务逻辑 如果是普通 Servlet:调用service()方法,再根据请求方式(GET/POST)调用doGet()/doPost(),处理完后把结果写入HttpServletResponse; 如果是 SpringMVC:先到 DispatcherServlet,再通过 HandlerMapping 找到 Controller 方法,处理业务、渲染视图,最终封装响应。 返回响应响应对象从 Context → Host → Engine → Connector 逐层返回,Connector 把HttpServletResponse解析成 HTTP 响应报文,通过 TCP 连接返回给客户端,完成一次请求。 三、精简版(30 秒速答) "Tomcat 处理请求分 4 个核心环节: Connector 接收请求,封装成 Request/Response; 依次经过 Engine(引擎)→ Host(虚拟主机)→ Context(项目),匹配到对应的 Servlet; Servlet 处理业务逻辑,封装响应; 响应沿原路径返回,Connector 把响应解析成 HTTP 报文发给客户端。"

23.java 8 是非常重要的版本,核心提升了代码简洁性和并发效率,主要特性有:
  1. Lambda 表达式,简化匿名内部类,依赖函数式接口,让代码更简洁;

  2. Stream API,对集合做过滤、映射等聚合操作,支持并行处理,比传统循环效率更高;

  3. 新日期时间 API,解决旧 API 线程不安全问题,比如 LocalDateTime、DateTimeFormatter 这些类,不可变且语义化;

  4. 还有默认方法,让接口可以有具体实现,避免接口升级影响实现类;另外 Optional 能有效避免空指针,方法引用简化 Lambda 写法。

相关推荐
C++ 老炮儿的技术栈2 小时前
c++常见配置文件格式 JSON、INI、XML、YAML 它们如何解析
xml·开发语言·c++·windows·qt·json
C++chaofan2 小时前
RPC框架容错机制深度解析
java·开发语言·后端·性能优化·高并发·juc·容错机制
2301_795741792 小时前
在构建企业级文生视频存储架构时,RustFS相比传统存储方案有哪些独特优势?
开发语言·python·pygame
تچ快乐杂货店يچ2 小时前
基于前后端分离的在线考试系统(微服务架构 + RBAC权限 + AI助手)
java·vue.js·spring boot·spring cloud·微服务·架构·typescript
奋斗的老史2 小时前
List和Map互转
java
是娇娇公主~2 小时前
C++ 中 std::vector 和 std::list 的区别
开发语言·c++·list
镜中月ss2 小时前
QT中的资源树
开发语言·qt·qml
superantwmhsxx2 小时前
SpringSecurity相关jar包的介绍
java·jar
小陈工2 小时前
2026年3月25日技术资讯洞察:开源芯片革命、Postgres文件系统与AI Agent安全新范式
开发语言·数据库·人工智能·python·安全·web安全·开源