高频java基础面试题及答案_第1页
高频java基础面试题及答案_第2页
高频java基础面试题及答案_第3页
高频java基础面试题及答案_第4页
高频java基础面试题及答案_第5页
已阅读5页,还剩15页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

高频java基础面试题及答案Java跨平台的原理是什么?Java程序的跨平台性依赖于Java虚拟机(JVM)的存在。开发者编写的Java源代码会被编译成与平台无关的字节码文件(.class),不同平台的JVM会将字节码文件翻译成对应操作系统能识别的机器指令。因此,只要目标设备安装了对应版本的JVM,同一个字节码文件就能在不同操作系统上运行。这种“一次编写,到处运行”的特性,核心在于JVM对字节码的解析执行,而非Java语言本身跨平台。JDK、JRE、JVM三者的区别是什么?JDK(JavaDevelopmentKit)是Java开发工具包,包含JRE和开发工具(如javac编译器、jdb调试器、javadoc文档提供工具等),是开发者使用的核心工具集。JRE(JavaRuntimeEnvironment)是Java运行时环境,包含JVM和运行Java程序所需的核心类库(如java.lang、java.util等),用于运行已编译的Java程序。JVM(JavaVirtualMachine)是Java虚拟机,负责执行字节码并与操作系统交互,是Java跨平台的关键。三者关系为:JDK包含JRE,JRE包含JVM。基本数据类型和引用数据类型有什么区别?Java中数据类型分为基本类型(PrimitiveType)和引用类型(ReferenceType)。基本类型共有8种,包括4种整数型(byte、short、int、long)、2种浮点型(float、double)、1种字符型(char)和1种布尔型(boolean)。基本类型变量直接存储值,内存分配在栈中(除long和double外,其他基本类型在栈中占固定大小)。引用类型包括类、接口、数组,变量存储的是对象的内存地址(引用),对象本身存储在堆中。引用类型默认值为null,基本类型有各自的默认值(如int默认0,boolean默认false)。此外,基本类型的运算效率通常高于引用类型,因为无需寻址操作。面向对象的三大特性是什么?各自的含义是什么?面向对象的三大核心特性是封装、继承、多态。封装指将对象的属性和方法隐藏在内部,仅通过公开接口(如getter/setter方法)对外提供访问,限制外部直接操作内部状态,提高安全性和可维护性。例如,类中私有属性通过公共方法修改。继承允许一个类(子类)继承另一个类(父类)的属性和方法,子类可扩展新功能或重写父类方法,实现代码复用。Java中通过extends关键字实现单继承(类),但接口支持多继承。多态指同一行为在不同对象上表现出不同形态,分为编译时多态(方法重载,Overload)和运行时多态(方法重写,Override)。运行时多态的实现依赖继承、方法重写和父类引用指向子类对象(如Animala=newCat()),调用方法时实际执行子类重写后的逻辑。重载(Overload)和重写(Override)的区别是什么?重载发生在同一个类中,指多个方法具有相同的方法名但参数列表不同(参数类型、数量或顺序不同),与返回值类型无关。编译器根据调用时传入的参数类型和数量匹配具体方法,属于编译时多态。例如:publicvoidprint(inta)和publicvoidprint(Strings)是重载。重写发生在子类和父类之间,子类重新定义父类中具有相同方法签名(方法名、参数列表、返回值类型完全相同)的方法,用于实现子类特有的行为。重写需满足:子类方法访问权限不能小于父类(如父类方法是protected,子类不能是默认或private);子类方法不能抛出比父类更宽泛的异常(运行时异常除外)。重写是运行时多态的体现,调用时根据实际对象类型执行对应方法。抽象类和接口的区别是什么?抽象类使用abstract关键字声明,可包含抽象方法(无方法体)和具体方法(有方法体)。接口在Java8前只能定义抽象方法和常量(publicstaticfinal),Java8后支持默认方法(default)和静态方法(static),Java9后支持私有方法。类只能继承一个抽象类,但可实现多个接口。抽象类中的成员变量可以是任意访问修饰符(private、protected、public),接口中的变量默认是publicstaticfinal(必须初始化)。抽象类的设计目的是为子类提供公共模板,共享部分实现;接口的设计目的是定义行为规范,实现多继承能力。例如,抽象类Animal可定义run()抽象方法和eat()具体方法,而接口Flyable定义fly()方法,鸟类可继承Animal并实现Flyable。String、StringBuilder、StringBuffer的区别是什么?String是不可变类,底层使用final修饰的char数组(JDK9后改为byte数组)存储字符,每次对String的修改操作(如拼接、替换)都会提供新的String对象,性能较低。StringBuilder和StringBuffer是可变类,底层数组可扩容,修改操作在原对象上进行,性能更高。StringBuffer的方法使用synchronized修饰,是线程安全的;StringBuilder未加锁,线程不安全但性能更优。因此,单线程环境下字符串频繁修改推荐使用StringBuilder,多线程环境下使用StringBuffer,字符串不修改或少量修改时使用String。HashMap的底层实现是什么?JDK7和JDK8有哪些区别?HashMap基于哈希表实现,通过键的哈希值确定存储位置,解决哈希冲突的方式是链地址法。JDK7中,HashMap的底层结构是“数组+链表”:数组是Entry类型的哈希桶(table),每个Entry包含key、value、hash和next指针(指向链表下一个节点)。当插入元素时,计算key的hashCode()并通过扰动函数(二次哈希)减少碰撞,然后用(n-1)&hash计算桶索引。若该位置已有元素,通过链表追加。JDK8对底层结构进行了优化:1.数据结构改为“数组+链表+红黑树”,当链表长度≥8且数组长度≥64时,链表转换为红黑树(查询时间复杂度从O(n)降至O(logn));当红黑树节点数≤6时,退化为链表。2.哈希扰动函数简化,JDK7中hash()方法进行了4次位运算+5次异或,JDK8简化为(h=key.hashCode())^(h>>>16),仅一次异或,减少计算开销。3.插入方式从JDK7的头插法(新节点插入链表头部)改为JDK8的尾插法(新节点插入链表尾部),避免多线程扩容时的链表成环问题(但HashMap本身仍非线程安全)。4.扩容机制优化,JDK7扩容时重新计算每个元素的哈希值和索引,JDK8通过判断原索引+旧容量是否等于新索引(因为扩容是2的幂次,新容量是旧的2倍),避免重复计算哈希。ConcurrentHashMap如何实现线程安全?JDK7和JDK8的差异是什么?ConcurrentHashMap是线程安全的哈希表,JDK7和JDK8的实现机制不同。JDK7采用“分段锁(Segment)”机制,继承ReentrantLock的Segment类作为锁的基本单元,每个Segment对应一个哈希桶的子集(默认16个Segment)。当操作不同Segment时,锁互不影响,提高并发度。每个Segment内部维护一个HashEntry数组,插入、删除等操作需获取对应Segment的锁。JDK8放弃了分段锁,改为“CAS+synchronized”的轻量级锁机制:1.底层结构与HashMap相同(数组+链表+红黑树),以节点(Node)为锁的基本单位。2.插入元素时,首先通过CAS尝试插入(比较并交换),若CAS失败(说明有竞争),则使用synchronized锁定该节点所在的链表头或红黑树的根节点。3.扩容时采用多线程协作机制,每个线程处理一部分旧数组的迁移,通过sizeCtl变量标记扩容状态,避免阻塞其他线程。JDK8的优化减少了锁的粒度(从Segment到单个节点),降低了锁竞争,同时利用synchronized的锁升级(偏向锁→轻量级锁→重量级锁)提高性能,并发度和吞吐量优于JDK7的分段锁。ArrayList和LinkedList的区别是什么?ArrayList基于动态数组实现,支持随机访问(通过索引O(1)时间获取元素),但插入和删除操作(尤其在中间位置)需要移动元素,时间复杂度O(n)。默认初始容量为10,当元素超过容量时触发扩容(新容量=旧容量×1.5),扩容需复制数组,性能有一定损耗。LinkedList基于双向链表实现(JDK1.6前为循环链表,后改为双向链表),每个节点包含前驱(prev)和后继(next)指针。插入和删除操作只需修改相邻节点的指针(O(1)时间,若已知节点位置),但随机访问需遍历链表(O(n)时间)。此外,LinkedList还实现了Deque接口,支持队列和双端队列操作(如addFirst()、removeLast())。因此,若频繁随机访问元素,选ArrayList;若频繁插入/删除(尤其在两端),选LinkedList。Error和Exception的区别是什么?运行时异常和检查型异常的区别?Error和Exception都继承自Throwable类。Error表示JVM无法处理的严重错误(如OutOfMemoryError、StackOverflowError、NoClassDefFoundError),通常由系统级问题引起,程序无法捕获或恢复,应避免尝试处理。Exception表示程序可处理的异常,分为运行时异常(RuntimeException及其子类)和检查型异常(非RuntimeException的Exception子类)。运行时异常(如NullPointerException、ArrayIndexOutOfBoundsException、IllegalArgumentException)由程序逻辑错误导致,编译器不强制要求处理(可捕获也可不捕获)。检查型异常(如IOException、SQLException、ClassNotFoundException)由外部因素(如文件不存在、数据库连接失败)引起,编译器强制要求显式处理(通过try-catch捕获或throws声明抛出)。try-catch-finally中,如果catch块有return语句,finally块会执行吗?执行顺序是怎样的?finally块中的代码一定会执行(除非在try或catch块中调用System.exit(0)终止JVM)。若catch块中有return语句,执行顺序为:执行try块→出现异常→跳转到对应的catch块→执行catch块中return前的代码→执行finally块→回到catch块执行return。需要注意,若finally块中修改了变量值,可能影响返回结果。例如:```javapublicinttest(){inti=1;try{i=2;thrownewRuntimeException();}catch(Exceptione){i=3;intresult=i;returnresult;//此时result=3}finally{i=4;//修改i的值,但不影响已确定的返回值result}}//最终返回3,而非4```若finally块中也有return语句,则会覆盖catch块的return,直接返回finally中的结果(不推荐,可能导致异常被吞)。线程的生命周期有哪些状态?如何转换?Java线程的生命周期包含6种状态(Thread.State枚举):1.NEW(新建):线程被创建但未调用start()方法。2.RUNNABLE(可运行):调用start()后进入,包括操作系统中的“就绪”(等待CPU调度)和“运行中”状态。3.BLOCKED(阻塞):线程等待获取监视器锁(如进入synchronized修饰的方法/代码块时未获取到锁)。4.WAITING(无限等待):线程调用wait()(无超时参数)、join()(无超时参数)或LockSupport.park()后进入,需其他线程调用notify()/notifyAll()或unpark()唤醒。5.TIMED_WAITING(计时等待):调用sleep(long)、wait(long)、join(long)或parkNanos(long)/parkUntil(long)后进入,超时或被唤醒后回到RUNNABLE。6.TERMINATED(终止):线程执行完毕或因异常退出。状态转换示例:NEW→start()→RUNNABLE→获取不到锁→BLOCKED→获取锁→RUNNABLE→调用wait()→WAITING→其他线程notify()→RUNNABLE→调用sleep(1000)→TIMED_WAITING→超时→RUNNABLE→执行完毕→TERMINATED。synchronized和Lock的区别是什么?synchronized是Java关键字,Lock是java.util.concurrent.locks包下的接口(如ReentrantLock实现)。主要区别:1.锁的获取与释放:synchronized是隐式锁,进入同步块自动获取锁,退出(正常或异常)自动释放。Lock需显式调用lock()获取锁,unlock()释放(通常在finally块中调用)。2.锁的特性:synchronized是非公平锁(不保证等待线程的获取顺序),Lock可通过构造函数指定公平锁(按等待队列顺序获取)或非公平锁。Lock支持可中断获取(lockInterruptibly())、尝试获取(tryLock())和超时获取(tryLock(long,TimeUnit)),synchronized无法中断,只能等待锁释放。3.锁的粒度:synchronized锁定的是对象(实例锁)或类(类锁),锁粒度较粗。Lock支持更细粒度的锁分离(如ReentrantReadWriteLock的读锁和写锁),允许多个读线程同时访问,写线程独占。4.性能:早期版本synchronized性能较差(重量级锁),但JDK6后引入锁升级(偏向锁→轻量级锁→重量级锁)优化,性能与Lock接近。高竞争场景下,Lock的可中断、尝试获取等特性更灵活。volatile的作用是什么?volatile是轻量级的同步机制,用于保证变量的可见性和禁止指令重排序,但不保证原子性。可见性指当一个线程修改了volatile变量的值,其他线程能立即看到最新值(通过内存屏障实现,禁止CPU缓存,直接读写主内存)。指令重排序指编译器或CPU为优化性能重新排列指令顺序,可能导致多线程环境下的逻辑错误。volatile通过插入内存屏障(LoadLoad、StoreStore等)禁止编译器和CPU对volatile变量的读写操作进行重排序。例如,单例模式的双重检查锁定(DCL)中,需将实例变量声明为volatile,防止指令重排序导致其他线程获取到未初始化的实例。但volatile无法保证复合操作的原子性(如i++包含读取、修改、写入三步),此时需使用AtomicInteger或synchronized。线程池的核心参数有哪些?工作流程是怎样的?线程池通过ThreadPoolExecutor创建,核心参数包括:1.corePoolSize(核心线程数):线程池长期保留的线程数,即使空闲也不会销毁(除非设置allowCoreThreadTimeOut为true)。2.maximumPoolSize(最大线程数):线程池允许的最大线程数,核心线程数+临时线程数(临时线程在空闲时间超过keepAliveTime后销毁)。3.keepAliveTime(存活时间):临时线程的空闲存活时间,超时后销毁。4.unit(时间单位):keepAliveTime的单位(如TimeUnit.SECONDS)。5.workQueue(任务队列):存储待执行任务的阻塞队列,常用类型有ArrayBlockingQueue(有界)、LinkedBlockingQueue(无界/有界)、SynchronousQueue(无缓冲,直接提交)、PriorityBlockingQueue(优先级队列)。6.threadFactory(线程工厂):创建线程的工厂,可自定义线程名称、优先级等。7.handler(拒绝策略):当任务队列已满且线程数达到maximumPoolSize时,对新任务的处理策略,默认是AbortPolicy(抛出RejectedExecutionException),还包括CallerRunsPolicy(调用者线程执行)、DiscardPolicy(丢弃任务)、DiscardOldestPolicy(丢弃队列中最旧任务)。工作流程:提交任务→若当前线程数<corePoolSize,创建新线程执行任务→若≥corePoolSize,将任务加入workQueue→若workQueue已满且当前线程数<maximumPoolSize,创建临时线程执行任务→若workQueue已满且线程数≥maximumPoolSize,触发拒绝策略。JVM的内存结构分为哪些部分?各自的作用是什么?JVM内存结构(运行时数据区)包括以下部分:1.程序计数器(ProgramCounterRegister):较小的内存空间,存储当前线程执行的字节码指令的地址(行号)。线程私有,用于线程切换后恢复执行位置。2.虚拟机栈(JavaVirtualMachineStack):线程私有,每个方法调用对应一个栈帧(包含局部变量表、操作数栈、动态链接、方法出口等)。存储基本类型变量、对象引用和returnAddress。若线程请求的栈深度超过最大值,抛出StackOverflowError;若栈扩展失败,抛出OutOfMemoryError。3.本地方法栈(NativeMethodStack):与虚拟机栈类似,用于执行本地方法(如用C/C++编写的方法)。HotSpot虚拟机将其与虚拟机栈合并。4.堆(Heap):所有线程共享,存储对象实例和数组。JVM管理的最大内存区域,可通过-Xms(初始大小)和-Xmx(最大大小)设置。堆是垃圾回收(GC)的主要区域,分为新生代(Eden区、Survivor0、Survivor1)和老年代(Tenured区)。5.方法区(MethodArea):线程共享,存储类信息(如类名、父类、接口、方法字节码)、常量、静态变量、即时编译器编译后的代码等。JDK7前方法区实现为永久代(PermGen),使用堆内存;JDK8后改为元空间(MetaSpace),使用本地内存(NativeMemory),避免永久代的内存溢出问题。6.运行时常量池(RuntimeConstantPool):方法区的一部分,存储编译期提供的字面量(如字符串、数字)和符号引用(如类名、方法名、字段名),运行时可动态添加(如Sern())。类加载的过程分为哪几个阶段?各阶段的任务是什么?类加载过程分为加载、链接(验证、准备、解析)、初始化三个阶段。1.加载:通过类加载器(ClassLoader)将类的字节码文件(如.class)加载到内存,提供java.lang.Class对象。加载的字节码来源可以是本地文件、网络、动态提供(如Proxy)等。2.链接:验证:确保字节码文件符合JVM规范,防止恶意或错误代码。包括文件格式验证(如魔数0xCAFEBABE)、元数据验证(如父类是否存在)、字节码验证(指令合法性)、符号引用验证(如方法是否存在)。准备:为类的静态变量(static)分配内存并设置初始值(如int类型初始为0,引用类型为null)。静态常量(staticfinal)在编译时确定值,准备阶段直接赋值。解析:将符号引用(如“java/lang/Object”)替换为直接引用(内存地址)。解析可发生在初始化阶段之后(延迟解析),支持动态绑定。3.初始化:执行类的初始化代码(静态变量赋值和静态代码块),由JVM自动调用<clinit>()方法。初始化触发时机包括:实例化类、调用静态方法、访问静态变量(非final)、反射调用类、初始化子类(父类先初始化)、主类(包含main方法的类)启动时。常见的垃圾回收算法有哪些?各自的优缺点是什么?常见的垃圾回收(GC)算法包括:1.标记-清除(Mark-Sweep):首先标记所有需要回收的对象(可达性分析:从GCRoots出发,标记不可达对象),然后清除标记的对象。优点是实现简单,无需移动对象。缺点是会产生内存

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论