版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Java基础部分面试题(2025年)附答案1.自动装箱与拆箱的底层实现是什么?Integer的缓存机制有哪些需要注意的细节?自动装箱通过调用包装类的`valueOf()`方法实现,例如`Integeri=10`会编译为`Integeri=Integer.valueOf(10)`;拆箱通过调用`intValue()`方法实现,例如`intj=i`会编译为`intj=Value()`。Integer的缓存机制通过`IntegerCache`静态内部类实现,默认缓存范围是-128到127(可通过JVM参数`-XX:AutoBoxCacheMax`调整上限)。当数值在此范围内时,`valueOf()`会直接返回缓存的对象,超出范围则新建对象。需要注意:-缓存仅适用于自动装箱和显式调用`valueOf()`,`newInteger()`始终创建新对象;-不同包装类的缓存范围不同(如Byte缓存-128~127,Long缓存-128~127,Character缓存0~127);-缓存是线程安全的,因为`IntegerCache`类在类加载时初始化,由类加载机制保证线程安全。2.Java中方法参数传递是值传递还是引用传递?对象作为参数传递时,修改属性和重新赋值有何区别?Java中只有值传递。基本类型传递的是值的副本,对象类型传递的是对象引用的副本。当对象作为参数传递时:-修改对象的属性会影响原对象(因为引用副本指向同一对象);-对参数引用重新赋值(如`obj=newObject()`)不会影响原引用(因为副本指向了新对象,原引用仍指向旧对象)。示例:```javapublicstaticvoidchangeValue(intx){x=10;}//基本类型,调用后原变量不变publicstaticvoidchangeRef(MyClassobj){obj.setValue(10);}//修改属性,原对象属性改变publicstaticvoidchangeRef2(MyClassobj){obj=newMyClass();}//重新赋值,原引用不变```3.String、StringBuilder、StringBuffer的区别及适用场景?JDK9之后String的底层存储有何变化?-String:不可变字符序列,底层使用`finalchar[]`存储(JDK9前),JDK9后改为`finalbyte[]`(LATIN1或UTF16编码,节省空间)。所有修改操作(如`concat()`、`substring()`)都会提供新对象。-StringBuffer:可变字符序列,线程安全(方法用`synchronized`修饰),适用于多线程下的频繁拼接。-StringBuilder:可变字符序列,线程不安全,性能更高,适用于单线程下的频繁拼接。JDK9优化String底层为`byte[]`的原因:多数字符串仅包含ASCII字符(1字节),用`char[]`(2字节)存储浪费空间,改为`byte[]`并通过`coder`字段记录编码(0为LATIN1,1为UTF16),减少内存占用。4.重写(Override)与重载(Overload)的核心区别是什么?构造方法能否被重写或重载?-重写:子类重新定义父类的非静态、非final、非private方法,要求方法名、参数列表、返回值类型(或协变返回类型)完全相同,访问权限不能严于父类。用于实现多态。-重载:同一类中方法名相同但参数列表(类型、顺序、个数)不同,与返回值类型无关。用于提供多种调用方式。构造方法可以重载(通过不同参数列表定义多个构造方法),但不能重写(构造方法属于类自身,子类无法继承父类构造方法)。5.抽象类与接口的区别(JDK8及以上)?SealedClasses(密封类)如何限制继承?-抽象类:可包含抽象方法、具体方法、成员变量(非静态/静态),子类通过`extends`继承,只能单继承。-接口:JDK8前仅能定义抽象方法和静态常量;JDK8后支持默认方法(`default`)和静态方法;JDK9后支持私有方法。子类通过`implements`实现,可多实现。SealedClasses(JDK17引入)通过`sealed`修饰类,并使用`permits`指定允许继承的子类,限制类的继承范围。例如:```javapublicabstractsealedclassShapepermitsCircle,Rectangle{}finalclassCircleextendsShape{}//必须是final或sealed```6.简述Java异常处理机制中CheckedException和UncheckedException的分类及处理要求?try-with-resources的原理是什么?-CheckedException(受检异常):继承自`Exception`(非`RuntimeException`),如`IOException`、`SQLException`。必须显式处理(捕获或声明抛出),否则编译失败。-UncheckedException(非受检异常):继承自`RuntimeException`或`Error`,如`NullPointerException`、`ArrayIndexOutOfBoundsException`。无需显式处理,由JVM或上层调用者处理。try-with-resources(JDK7引入)用于自动关闭实现`AutoCloseable`接口的资源(如`FileInputStream`)。原理是编译器自动提供`finally`块,按资源声明逆序调用`close()`方法(即使发生异常)。资源对象需在`try`括号内声明,作用域仅限于`try`块。7.ArrayList与LinkedList的底层结构和性能差异?为什么ArrayList的`add(intindex,Eelement)`在中间插入时效率较低?-ArrayList:底层是动态扩容的数组(`transientObject[]elementData`),支持O(1)时间随机访问(通过索引),但插入/删除(尤其中间位置)需移动元素,时间复杂度O(n)。-LinkedList:底层是双向链表(`Node`节点包含prev、next、item),插入/删除(已知节点位置)时间复杂度O(1),但随机访问需遍历链表,时间复杂度O(n)。ArrayList中间插入时,需将`index`后所有元素后移(`System.arraycopy()`),移动次数为`size-index`,因此当`index`接近0时性能最差(需移动全部元素)。8.HashMap的底层结构(JDK8+)?为什么容量是2的幂次?红黑树转换的阈值为什么是8?JDK8+HashMap底层是“数组+链表+红黑树”结构:-数组(`Node[]table`):存储链表或红黑树的头节点,初始容量16(`DEFAULT_INITIAL_CAPACITY`),负载因子0.75(平衡空间与查询效率)。-链表:当桶中节点数≤7时(`TREEIFY_THRESHOLD`为8,但转换红黑树还需容量≥64),以链表形式存储(`Node`节点)。-红黑树:当桶中节点数≥8且容量≥64时,链表转换为红黑树(`TreeNode`节点),降低查找时间复杂度至O(logn)。容量设计为2的幂次是为了通过位运算快速计算哈希桶位置(`(n-1)&hash`),比取模运算更高效。若容量非2的幂次,`n-1`的二进制位不全为1,会导致哈希碰撞概率增加。红黑树转换阈值设为8的原因:链表节点数符合泊松分布,当负载因子0.75时,节点数≥8的概率极低(约0.00000006),此时转换红黑树可避免链表过长导致的查询性能下降;而阈值设为8可平衡链表和红黑树的维护成本(红黑树插入/删除的旋转操作比链表复杂)。9.ConcurrentHashMap如何实现线程安全(JDK7vsJDK8)?put()方法的执行流程(JDK8)?JDK7:使用分段锁(`Segment`数组,继承`ReentrantLock`),每个`Segment`管理一个链表,默认16个段,支持16个线程并发写(不同段)。JDK8:放弃分段锁,采用`CAS+synchronized`实现线程安全:-数组节点(`Node`)用`volatile`修饰,保证可见性;-插入时,若桶为空(`tab[i]==null`),通过CAS尝试写入;-若桶不为空且头节点未被锁定(`f.hash!=MOVED`),使用`synchronized`锁定头节点(链表头或红黑树根),避免锁定整个桶;-扩容时通过`ForwardingNode`标记正在迁移的桶,其他线程协助扩容(`helpTransfer()`)。JDK8put()流程:1.计算key的哈希值(`hash=key.hashCode()^(hash>>>16)`);2.检查数组是否初始化,未初始化则调用`initTable()`(CAS+自旋保证线程安全);3.计算桶位置`i=(n-1)&hash`,若桶为空,CAS插入新节点;4.若桶头节点哈希为`-1`(`MOVED`),说明正在扩容,协助扩容;5.否则,`synchronized`锁定头节点,遍历链表/红黑树:-链表:查找是否存在相同key,存在则覆盖值;不存在则添加至链表尾部(JDK8链表尾插),若长度≥8且容量≥64,转换为红黑树;-红黑树:调用`putTreeVal()`插入节点;6.增加`size`计数(通过`CounterCell`数组分散计数,避免CAS竞争),若超过阈值(`sizeCtl`)则扩容。10.线程的生命周期有哪些状态?如何从RUNNABLE转换为BLOCKED?Java线程状态(`Thread.State`枚举):-NEW:线程创建但未调用`start()`;-RUNNABLE:可运行状态(包括正在CPU执行或等待调度);-BLOCKED:等待获取监视器锁(如进入`synchronized`同步块/方法时未获取到锁);-WAITING:等待其他线程唤醒(调用`wait()`、`join()`无超时、`LockSupport.park()`);-TIMED_WAITING:定时等待(`sleep(long)`、`wait(long)`、`join(long)`、`parkNanos()`);-TERMINATED:线程执行完毕或异常终止。从RUNNABLE到BLOCKED的场景:当线程尝试进入`synchronized`修饰的代码块/方法时,若该锁已被其他线程持有,则线程状态变为BLOCKED,直到获取到锁。11.synchronized的锁升级过程(偏向锁→轻量级锁→重量级锁)是怎样的?锁的存储位置在哪里?锁升级是为了优化锁的性能,减少线程切换开销,过程如下:-偏向锁(JDK6默认开启):首次获取锁时,JVM在对象头(MarkWord)中记录当前线程ID,后续同一线程再次获取锁时无需CAS操作,只需检查线程ID是否匹配。若其他线程竞争锁,偏向锁撤销(升级为轻量级锁)。-轻量级锁:竞争线程通过CAS尝试将对象头的MarkWord替换为指向自己栈中锁记录的指针。若成功,获取轻量级锁;若失败(存在竞争),升级为重量级锁。-重量级锁:依赖操作系统互斥量(Mutex),竞争线程进入阻塞状态,需内核态切换,开销大。锁的信息存储在对象头中,对象头包含MarkWord(存储哈希码、GC分代年龄、锁状态等)和类型指针(指向类元数据)。数组对象还包含长度信息。12.volatile的作用是什么?如何保证可见性和禁止指令重排?volatile的两大特性:-可见性:保证被修饰变量的修改对所有线程可见。JVM通过在写操作后插入`StoreStore`屏障,读操作前插入`LoadLoad`屏障,确保变量修改后立即刷新到主内存,其他线程读取时从主内存获取最新值。-禁止指令重排:通过内存屏障限制编译器和CPU的重排序。写操作后插入`StoreLoad`屏障,读操作前插入`LoadStore`屏障,确保volatile变量的操作顺序不被重排。示例:单例模式双重检查锁定(DCL)中,`instance`需用volatile修饰,避免指令重排导致其他线程获取到未初始化的对象(`newSingleton()`可分为分配内存、初始化对象、设置引用三步,重排可能导致第二步未完成时第三步先执行)。13.线程池的核心参数有哪些?拒绝策略有哪几种?如何合理配置线程数?线程池(`ThreadPoolExecutor`)核心参数:-`corePoolSize`:核心线程数(即使空闲也保留的线程数);-`maximumPoolSize`:最大线程数(核心线程+临时线程);-`keepAliveTime`:临时线程空闲存活时间;-`unit`:存活时间单位;-`workQueue`:任务队列(存储待执行的任务);-`threadFactory`:线程工厂(创建工作线程);-`handler`:拒绝策略(任务队列和线程池均满时的处理方式)。拒绝策略(`RejectedExecutionHandler`实现类):-`AbortPolicy`(默认):抛出`RejectedExecutionException`;-`CallerRunsPolicy`:调用者线程执行任务;-`DiscardPolicy`:直接丢弃任务;-`DiscardOldestPolicy`:丢弃队列中最旧的任务,尝试重新提交当前任务。线程数配置参考:-CPU密集型:线程数≈CPU核心数(+1防止页缺失);-IO密集型:线程数≈CPU核心数×(1+平均等待时间/平均执行时间)(可通过监控工具统计等待时间与执行时间的比值);-混合任务:拆分任务类型,或通过压测确定最优值。14.BIO、NIO、AIO的区别?NIO的Buffer有哪些核心属性?-BIO(阻塞IO):线程发起IO操作后阻塞,直到完成(如`ServerSocket.accept()`),适用于连接数少且固定的场景。-NIO(非阻塞IO,JDK1.4引入):基于事件驱动,通过`Selector`监控多个`Channel`的IO事件(读、写、连接、接收),线程仅在事件触发时处理,适用于高并发、短连接场景。-AIO(异步IO,JDK7引入):IO操作由OS完成后回调通知线程(`CompletionHandler`),真正的异步非阻塞,适用于长连接、大文件传输场景。NIOBuffer核心属性(`java.nio.Buffer`):-`capacity`:缓冲区容量(固定,创建时指定);-`position`:当前操作位置(读/写的起始点);-`limit`:可操作的上限(读模式下为写操作的position,写模式下为capacity);-`mark`:标记位置(通过`mark()`记录,`reset()`恢复)。状态转换:写模式→读模式时调用`flip()`(`limit=position;position=0`);读模式→写模式时调用`clear()`(`position=0;limit=capacity`)或`compact()`(保留未读数据,`position=未读数据长度;limit=capacity`)。15.JVM内存区域如何划分?堆和栈的主要区别?JVM内存区域(JDK8+):-程序计数器:记录当前线程执行的字节码行号,线程私有,唯一无OOM的区域。-虚拟机栈:存储栈帧(局部变量表、操作数栈、动态链接、方法出口),线程私有,栈深度过深抛出`StackOverflowError`,扩展失败抛出`OutOfMemoryError`(OOM)。-本地方法栈:与虚拟机栈类似,服务于本地方法(`native`方法),HotSpot与虚拟机栈合并。-堆(Heap):存放对象实例和数组,线程共享,是GC的主要区域,内存不足抛出OOM。-元空间(MetaSpace,JDK8取代永久代):存储类元数据、常量、静态变量(JDK7起字符串常量池移至堆),使用本地内存(NativeMemory),默认无固定大小限制,内存不足抛出OOM。堆与栈的区别:-存储内容:堆存对象实例,栈存局部变量(基本类型值、对象引用);-线程属性:堆是线程共享的,栈是线程私有的;-内存管理:堆由GC自动回收,栈随方法调用/返回自动入栈/出栈;-大小限制:堆通常较大(受JVM参数`-Xmx`限制),栈较小(受`-Xss`限制)。16.垃圾回收(GC)的标记阶段如何判断对象是否存活?分代收集理论的核心假设是什么?标记阶段判断对象存活的方法:-引用计数法:给对象添加引用计数器,引用时+1,失效时-1,计数器为0则回收。无法解决循环引用问题(如A引用B,B引用A,无其他引用时计数器均不为0),HotSpot未采用。-可达性分析(根搜索算法):以GCRoots为起点,通过引用链(ReferenceChain)遍历对象,不可达的对象标记为可回收。GCRoots包括:-虚拟机栈中局部变量表引用的对象;-方法区中类静态属性引用的对象;-方法区中常量引用的对象
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年保险练习题库附完整答案详解(网校专用)
- 2026年国开电大经济法律基础形考通关试卷(突破训练)附答案详解
- 2026年人才考核笔综合检测模拟卷【完整版】附答案详解
- 2026年国开电大成本会计形考押题练习试卷带答案详解
- 2026年导游服务理论考核自测题库附参考答案详解【黄金题型】
- 2026年国开电大建筑制图基础形考预测复习及答案详解(真题汇编)
- 2026年超星尔雅真题(综合题)附答案详解
- 2026年钳工技能实践考核练习题库及答案详解【基础+提升】
- 2026年国开电大金融基础形考预测复习含完整答案详解(各地真题)
- 2026年冬季消防安全知识竞赛模拟试题附完整答案详解(名校卷)
- 物业管理安全生产风险分级制度
- 中国移动自智网络白皮书(2024) 强化自智网络价值引领加速迈进L4级新阶段
- 免模装配一体化钢筋混凝土结构工业化体系(PI体系)研发及实践
- OQC检验重点培训资料
- 农业银行网点6S管理的灾害防范和应急措施
- 甲乙丙三方工程合作协议书范本
- 特种车结构与保险责任
- 475Q天然气发动机润滑系统设计说明书
- 林木种苗培训大纲
- 《科学探究:向心力 第1课时》示范公开课教学课件【物理鲁科版高中必修第二册(新课标)】
- 山东临工后市场运营思辨-定稿
评论
0/150
提交评论