目录

1. 重载和重写有什么区别?

2. ConcurrentHashMap是如何保证线程安全的?

3. 了解Java的包装类类型吗?为什么需要包装类?

4. 为什么JDK9要将String的底层实现由char[]改成byte[]?

5. String, StringBuffer 和 StringBuilder 的区别?

6. Java创建对象有几种方式?

7. final, finally, finalize 的区别?

8. Java支持多继承吗?

9. 介绍一下Java 8的新特性?

10. 什么是反射?反射有哪些应用场景呢?


1. 重载和重写有什么区别?

【回答话术】
这两个概念都属于多态,但发生的时间和作用对象不同:

  • 重载(Overload)

    • 作用对象:同一个类中。
    • 核心特征:方法名相同,参数列表不同(参数个数、类型、顺序)。与返回值类型和访问修饰符无关。
    • 发生时间:编译时多态(静态绑定)。
  • 重写(Override)

    • 作用对象:父子类之间(继承关系)。
    • 核心特征:子类方法签名必须与父类方法完全一致。子类方法的访问权限不能比父类更严格(如父类是protected,子类不能是private)。
    • 发生时间:运行时多态(动态绑定),依赖于对象的实际类型。

2. ConcurrentHashMap是如何保证线程安全的?

【回答话术】
ConcurrentHashMap 在不同版本的实现机制有所不同,面试时最好能区分说明:

  • JDK 1.7 版本

    • 采用了分段锁(Segment)机制。将数据分为多个段(Segment),每个段是一个独立的哈希表。
    • 操作时锁住的是具体的段,而不是整个表,从而减少了锁的竞争,提高了并发度。
  • JDK 1.8 版本

    • 废除了 Segment,改用 CAS + synchronized
    • 利用 Node 数组 + 链表 + 红黑树的结构。在插入或更新时,使用 CAS 保证原子性;当发生哈希冲突需要加锁时,只对链表的头节点或红黑树的根节点加 synchronized 锁,锁粒度更细,性能更好。

3. 了解Java的包装类类型吗?为什么需要包装类?

【回答话术】

  • 包装类类型

    • Java 为 8 种基本数据类型(byte, short, int, long, float, double, char, boolean)分别提供了对应的包装类(Byte, Short, Integer, Long, Float, Double, Character, Boolean)。
  • 为什么需要包装类

    • 泛型支持:Java 的泛型不支持基本数据类型,集合(如 List<T>)只能存储对象,因此必须使用包装类。
    • 集合存储:集合类(如 ArrayList, HashMap)要求存储对象,基本数据类型无法直接存入。
    • 方法参数:很多工具类方法(如 Integer.parseInt())要求参数是对象。
    • 空值表示:包装类可以为 null,而基本数据类型有默认值(如 int 默认为 0),这在数据库映射(表示空字段)时非常关键。

4. 为什么JDK9要将String的底层实现由char[]改成byte[]?

【回答话术】
主要是为了节省内存空间

  • 背景:在 JDK 8 及之前,String 底层使用 char[] 存储,char 占 2 个字节(UTF-16 编码)。但在实际应用中,大部分字符串(如英文、数字)只需要 1 个字节(Latin-1 编码)就能表示。
  • 优化:JDK 9 将底层改为 byte[],并引入了一个 coder 标识位。
    • 如果字符串只包含 Latin-1 字符(单字节),则用 byte[] 存储,节省一半内存。
    • 如果包含需要双字节表示的字符(如中文),则回退到双字节模式。
  • 效果:在大多数应用场景下,String 占用的堆内存减少了约 50%,显著降低了 GC 压力。

5. String, StringBuffer 和 StringBuilder 的区别?

【回答话术】
这三个类都用于处理字符串,但侧重点不同:

表格

特性StringStringBufferStringBuilder
可变性不可变(每次修改生成新对象)可变可变
线程安全线程安全(不可变即安全)线程安全(方法加了 synchronized非线程安全(无锁,性能高)
适用场景字符串内容极少变化,或作为常量。多线程环境下,需要频繁修改字符串。单线程环境下,需要频繁修改字符串(推荐)。

总结:操作次数少用 String,单线程大量操作用 StringBuilder,多线程大量操作用 StringBuffer


6. Java创建对象有几种方式?

【回答话术】
主要有以下 4 种方式:

  1. new 关键字:最常见的方式,调用构造器创建对象。
  2. Class.newInstance():通过反射机制创建对象(调用无参构造器)。
  3. Constructor.newInstance():更强大的反射方式,可以调用有参构造器,且可以访问私有构造器。
  4. clone() 方法:通过克隆(深拷贝或浅拷贝)创建对象,不调用任何构造器。
  5. 反序列化:通过 ObjectInputStream 从字节流中恢复对象。

7. final, finally, finalize 的区别?

【回答话术】
这三个词长得像,但功能完全不同:

  • final(关键字):用于修饰类、方法、变量。

    • 修饰类:不能被继承。
    • 修饰方法:不能被重写。
    • 修饰变量:如果是基本类型,值不可变;如果是引用类型,引用地址不可变(但对象内部属性可变)。
  • finally(代码块):用于异常处理。无论是否发生异常,finally 块中的代码都会被执行(常用于释放资源)。

  • finalize()(方法):是 Object 类的一个方法。在垃圾回收器准备回收对象之前,会调用此方法。注意:该方法已被废弃(deprecated),不推荐使用,因为无法保证何时被调用,且性能开销大。


8. Java支持多继承吗?

【回答话术】

  • 类层面不支持。Java 中一个类只能直接继承一个父类(单继承)。这是为了避免“菱形继承”带来的歧义问题(如 C++ 中的虚继承问题)。
  • 接口层面支持。一个接口可以继承多个接口。
  • 实现层面:Java 8 引入了接口的默认方法(default method),一个类可以实现多个接口,这在功能上实现了类似多继承的效果,但避免了父类方法冲突的问题(如果冲突,必须在子类中显式重写该方法)。

9. 介绍一下Java 8的新特性?

【回答话术】
Java 8 是一个里程碑版本,核心新特性包括:

  1. Lambda 表达式:简化代码,支持函数式编程风格(如 (a, b) -> a + b)。
  2. Stream API:用于集合的批量操作(过滤、映射、归约),支持函数式风格,代码更简洁。
  3. 接口默认方法:接口中可以有具体实现的方法(default 关键字),允许在不破坏现有实现类的情况下升级接口。
  4. Optional 类:用于解决空指针异常(NullPointerException),提供了一种优雅的判空方式。
  5. 新的日期时间 API (JSR 310):引入了 java.time 包(如 LocalDateLocalTime),解决了旧日期类(DateSimpleDateFormat)线程不安全和设计混乱的问题。

10. 什么是反射?反射有哪些应用场景呢?

【回答话术】

  • 什么是反射
    反射(Reflection)是指在运行时(Runtime)分析类的能力,以及操作对象的能力。通过反射,可以在程序运行时获取类的完整构造(属性、方法、构造器),甚至可以调用私有方法或修改私有属性。

  • 应用场景

    1. 框架开发:如 Spring(依赖注入、AOP)、MyBatis(ORM 映射)大量使用反射来动态创建对象和调用方法。
    2. 通用工具类:如 JSON 序列化/反序列化工具(Jackson, Gson),通过反射读取对象属性。
    3. 动态代理:Java 的动态代理机制(java.lang.reflect.Proxy)依赖反射来生成代理类。
    4. IDE 和调试工具:IDE 的代码提示、调试器查看对象属性等都依赖反射机制。
  • 缺点:破坏封装性、性能开销较大(比直接调用慢)、安全性问题。

更多推荐