【模拟面试|豆包模拟面试-2 Java基础】
昨天开始背的八股文 背了一点 背到面对对象那 前面记得还可以 后面没背的答不上来
1. 问题:Java 中基本数据类型有哪些,对应的包装类又是什么?
- 我的答案:基本数据类型包括数值型(int、short、byte、long、double、float)、字符型 char、布尔型 boolean;包装类除 int→Integer、char→Character 外,其余为首字母大写(如 double→Double)。包装类封装数据和行为,继承 Object,方便操作。✅
- 指导建议:包装类让基本类型拥有对象特性(如调用方法),自动装箱拆箱依赖包装类实现。注意 Integer 有缓存池(-128~127),直接赋值时会复用对象,超出范围则创建新对象。
2. 问题:Java 里自动装箱和拆箱是啥,举个例子?
- 我的答案:自动装箱是基本类型转包装类,拆箱是包装类转基本类型;JDK5 后无需手动调用 valueOf ()/intValue (),如 int i = 3; Integer num = i(装箱);int j = num(拆箱)。✅
- 指导建议:拆箱时若包装类为 null,会抛出 NullPointerException(例如 Integer i = null; int num = i;),实际开发中需提前判断非空,避免报错。
3. 问题:Java 里的 equals 和 == 有啥区别?
- 我的答案:equals 是 Object 方法,需重写;基本类型用 == 比较值,引用类型用 == 比较地址;equals 对引用类型默认比较地址,重写后可比较内容(如 String)。
- 指导建议:Object 类的 equals 本质就是 ==;String、Integer 等类重写 equals 后按内容比较,且必须同时重写 hashCode(否则会导致 HashMap 等集合存储异常);自定义类需手动重写 equals 和 hashCode,才能实现按内容比较对象。
4. 问题:Java 里的接口和抽象类有啥区别?
- 我的答案:抽象类可有成员变量、构造方法、具体方法;接口只有静态常量,JDK8 前全是抽象方法。抽象类用 extends 单继承,接口用 implements 多实现。✅
- 指导建议:JDK8 后接口新增默认方法(default 修饰,带方法体,子类可重写或直接使用)和静态方法(static 修饰,通过接口名调用);抽象类侧重 “is-a” 的继承关系(体现类的本质),接口侧重 “like-a” 的功能扩展(体现类的额外能力)。
5. 问题:Java 的异常体系结构是怎样的?
- 我的答案:异常继承 Exception,分运行时异常和编译时异常;用 try-catch-finally 处理,try 放可能出错的代码,catch 捕获,finally 必执行。❌
- 指导建议:异常体系顶层是 Throwable,分为 Error(系统级错误,如 OutOfMemoryError,程序无法处理,直接终止)和 Exception;运行时异常(RuntimeException 子类,如 NullPointerException、数组越界)无需强制处理,编译时异常(非 RuntimeException 子类,如 IOException)必须通过 try-catch 捕获或 throws 声明抛出;throw 用于抛出具体异常对象,throws 用于在方法声明处告知调用者可能抛出的异常类型。
6. 问题:List 和 Set 的主要区别?
- 我的答案:List 允许重复元素,有序(有索引);Set 不允许重复,无序。实现类:List 有 ArrayList、LinkedList;Set 有 HashSet、LinkedHashSet。
- 指导建议:Set 的去重逻辑依赖元素的 equals 和 hashCode 方法,自定义对象存入 Set 时,必须正确重写这两个方法;LinkedHashSet 是 Set 的特殊实现,虽不允许重复,但能保持元素的插入顺序;List 支持通过索引访问元素(如 get (int index)),Set 无索引,无法直接按位置获取元素。
7. 问题:HashMap 的底层实现原理,JDK8 前后区别?
- 我的答案:JDK8 前是数组 + 链表,JDK8 后链表长度 > 8 且数组容量 > 64 时转红黑树(<6 时转回链表)。初始容量 16,负载因子 0.75,超过则扩容。
- 指导建议:HashMap 的哈希计算采用 (n-1)&hash(n 为数组容量,必须是 2 的幂,保证哈希值均匀分布,减少冲突);JDK8 前链表插入用头插法(扩容时可能出现死锁),JDK8 后改用尾插法;put 流程:计算哈希值→定位数组桶位→桶内无元素则直接存入→有元素则判断 key 是否相同(相同则替换 value)→不同则链表 / 红黑树尾部插入。
8. 问题:线程的创建方式有哪几种?
- 我的答案:继承 Thread 类重写 run (),调用 start ();实现 Runnable 接口,传入 Thread 构造器后 start ();还有 Callable(记不清)。
- 指导建议:第三种创建方式是实现 Callable 接口,核心特点是重写的 call () 方法有返回值、可抛出异常;使用时需用 FutureTask 包装 Callable 对象,再传入 Thread 构造器,调用 start () 后,通过 FutureTask 的 get () 方法获取 call () 的返回值(get () 会阻塞线程,直到获取结果)。
9. 问题:Java 的类加载机制分哪几个阶段?
- 我的答案:记不清,好像有加载、验证、准备、解析、初始化?
- 指导建议:类加载机制的 5 个核心阶段按顺序执行:①加载(读取.class 文件二进制数据,在内存中生成 Class 对象);②验证(检查字节码合法性,如文件格式、元数据、字节码指令等);③准备(为静态变量分配内存,赋默认值,如 static int a=0,不执行静态代码块);④解析(将符号引用转换为直接引用,如类名、方法名转为内存地址);⑤初始化(执行静态代码块、为静态变量赋初始值,触发条件包括 new 对象、调用静态方法 / 变量等);类加载的核心是双亲委派模型,即子类加载器先委托父加载器加载类,避免类重复加载和核心类篡改。
10. 问题:String、StringBuffer 和 StringBuilder 的区别及使用场景?
- 我的答案:String 不可变,速度慢;StringBuffer 线程安全(同步方法),速度较快;StringBuilder 非线程安全,速度最快。
- 指导建议:String 的不可变性导致字符串拼接时会创建大量临时对象(如 String s = "a"+"b"+"c",编译后优化为常量,但循环拼接效率极低);单线程环境下字符串拼接、修改优先用 StringBuilder(无同步锁,效率最高);多线程环境下(如多线程操作同一个字符串缓冲区)必须用 StringBuffer(同步方法保证线程安全)。
11. 问题:反射机制是啥,有啥用?
- 我的答案:反射可访问私有成员,破坏封装,框架(如 Spring)常用。
- 指导建议:反射是 Java 的动态特性,指程序运行时动态获取类的信息(构造器、方法、字段)并调用的机制,核心是 Class 对象(获取方式:Class.forName ("全类名")、对象.getClass ()、类名.class);主要用途:框架解耦(如 Spring IOC 容器通过反射创建对象、注入属性)、注解解析(如 Spring @Autowired)、通用工具类开发;缺点是动态解析会产生性能损耗,且能突破访问权限(如访问私有方法),存在安全风险,非必要不使用。
12. 问题:IO 流分为哪几类,字节流和字符流的区别?
- 我的答案:分字节流(FileInputStream/FileOutputStream)和字符流(Reader/Writer);字节流处理二进制(如视频),不乱码;字符流处理文本,受编码影响,可能乱码。
- 指导建议:IO 流按操作数据单位分为字节流(8 位字节)和字符流(16 位字符);字节流基类是 InputStream(输入)和 OutputStream(输出),字符流基类是 Reader(输入)和 Writer(输出);字符流会自动处理编码转换(需指定编码格式,如 UTF-8),字节流需手动处理编码(如 new String (bytes, "UTF-8"));缓冲流(如 BufferedInputStream、BufferedReader)通过内部缓冲区减少 IO 操作次数,大幅提升读写效率,实际开发中建议优先使用。
13. 问题:线程的状态有哪些,如何转换?
- 我的答案:有阻塞态、运行态等,记不清具体。❌
- 指导建议:Java 线程的 6 种状态定义在 Thread.State 枚举中,具体状态及转换:①NEW(新建,new Thread 后未调用 start ());②RUNNABLE(可运行,调用 start () 后,包含 “就绪” 和 “运行” 两种状态,就绪态等待 CPU 调度,调度后进入运行态);③BLOCKED(阻塞,等待同步锁,如进入 synchronized 代码块未获取锁);④WAITING(等待,调用 wait ()、join () 等方法,无超时时间,需其他线程唤醒);⑤TIMED_WAITING(计时等待,调用 sleep (long)、wait (long) 等方法,超时后自动唤醒);⑥TERMINATED(终止,run () 方法执行完毕或线程异常终止)。
14. 问题:单例模式是什么,常见实现及区别?
- 我的答案:单例是全局唯一实例;饿汉式类加载时初始化,懒汉式按需加载❌
- c指导建议:常见实现方式及特点:①饿汉式(线程安全,实现简单,类加载时初始化,若实例未使用会浪费内存);②懒汉式(懒加载,非线程安全,需加 synchronized 锁,如双重检查锁 DCL+volatile,避免指令重排导致的空指针);③静态内部类(线程安全,懒加载,利用类加载机制,内部类被调用时才初始化实例,效率高);④枚举单例(天然线程安全,防反射、反序列化破坏单例,代码简洁,推荐高安全性场景)。
15. 问题:synchronized 怎么用,与 ReentrantLock 的区别?
- 我的答案:synchronized 是同步关键字,强制同步;Lock 需要手动 unlock。❌
- 指导建议:synchronized 的三种用法:①修饰普通方法(锁当前实例对象);②修饰静态方法(锁类的 Class 对象);③修饰代码块(锁括号内的对象,如 synchronized (this)、synchronized (类名.class));核心区别:synchronized 是 JVM 层面的锁,自动释放(异常或方法结束时),不可中断,非公平锁;ReentrantLock 是 API 层面的锁,需手动调用 unlock ()(建议在 finally 中调用,避免死锁),支持公平锁、可中断锁、超时获取锁等高级功能;适用场景:简单同步场景用 synchronized(简洁高效),复杂场景(如需要超时获取锁、多个条件变量)用 ReentrantLock。
16. 问题:泛型的作用及泛型擦除?
- 我的答案:泛型用 T 表示,可复用代码,支持 extend/super;泛型擦除是编译后字节码去掉泛型信息。
- 指导建议:泛型的核心作用:①类型安全(编译时检查类型,避免运行时类型转换异常,如 List<String>不能存入 Integer);②代码复用(一个泛型类 / 方法可处理多种类型,无需重复编写);泛型擦除是 Java 泛型的底层实现,编译后泛型参数会被擦除为其上限类型(未指定上限则为 Object,如 List<T>擦除为 List,<T extends Number>擦除为 List<Number>);运行时通过编译器隐式添加强制类型转换,实现类型安全;泛型通配符:<? extends T> 表示上限(只能接收 T 及子类),<? super T > 表示下限(只能接收 T 及父类)。
17. 问题:值传递和引用传递的区别,举例?
- 我的答案:值传递传值(如 int),修改不影响外部;引用传递传地址(如 String),修改影响外部。
- 指导建议:Java 严格遵循 “值传递”,无真正的引用传递:①基本类型值传递:传递的是变量的副本,方法内修改副本不影响原变量(如 public void change (int num){num=10;},调用时传 5,原变量仍为 5);②引用类型值传递:传递的是引用(内存地址)的副本,副本和原引用指向同一个对象,若修改对象的属性(如 p.age=20),会影响原对象;但如果重新赋值引用副本(如 p=new Person ()),原引用仍指向原对象,不影响外部。
18. 问题:线程池的核心参数及工作流程?
- 我的答案:有核心线程数、最大线程数,记不清其他。❌
- 指导建议:线程池的 7 个核心参数:①corePoolSize(核心线程数,长期存活,除非设置 allowCoreThreadTimeOut);②maximumPoolSize(最大线程数,核心线程 + 非核心线程的总数);③keepAliveTime(非核心线程空闲存活时间);④unit(keepAliveTime 的时间单位,如 TimeUnit.SECONDS);⑤workQueue(任务队列,存储等待执行的任务,如 LinkedBlockingQueue);⑥threadFactory(线程工厂,用于创建线程);⑦handler(拒绝策略,任务满时的处理方式);工作流程:提交任务→核心线程未满则创建核心线程执行→核心线程满则存入任务队列→队列满则创建非核心线程执行→非核心线程满(达到最大线程数)则触发拒绝策略;常见拒绝策略:AbortPolicy(抛异常)、CallerRunsPolicy(调用线程执行任务)、DiscardOldestPolicy(丢弃队列最老任务)、DiscardPolicy(直接丢弃任务)。
19. 问题:静态变量和实例变量的区别?
- 我的答案:静态变量属于类,类加载时初始化,共享;实例变量属于对象,随对象创建,生命周期同对象。调用:静态用类名.,实例用对象.。
- 指导建议:补充核心区别:①存储位置:静态变量存于方法区的静态域,实例变量存于堆内存的对象中;②生命周期:静态变量随类加载而创建,类卸载时销毁(程序运行期间一直存在),实例变量随对象创建而创建,对象被垃圾回收时销毁;③共享性:静态变量被类的所有对象共享(一个对象修改,其他对象可见),实例变量每个对象独立拥有(互不影响)。
20. 问题:Java 里的序列化是啥,怎么实现,Serializable 的作用?
- 我的答案:不会。 ❌
- 指导建议:序列化是将对象的状态(属性值)转换为字节流的过程,用于对象的存储(如存文件)或网络传输;反序列化是将字节流恢复为对象的过程;实现序列化的条件:①类实现 Serializable 接口(标记接口,无抽象方法,仅告知 JVM 该类可序列化);②类中声明 serialVersionUID 常量(序列化版本号,保证类修改后仍能正常反序列化,若未声明,JVM 会自动生成,类修改后生成的版本号变化,会导致反序列化失败);transient 关键字:标记的变量不参与序列化(如 transient String password; 序列化时 password 值会被忽略)。
