1. 深拷贝和浅拷贝的区别?

、 浅拷贝只复制对象的“表层”(引用地址),深拷贝则复制对象的“深层”(实际内容)。

  • 浅拷贝 (Shallow Copy):
    • 基本数据类型(如 int, boolean):复制的是具体的值。
    • 引用数据类型(如 String, List, 对象):复制的是内存地址(引用)
    • 结果: 新对象和原对象指向堆内存中的同一个实体。如果你修改了新对象里的引用类型数据,原对象也会被改变
    • 默认行为: Object 类提供的 clone() 方法默认是浅拷贝。
  • 深拷贝 (Deep Copy):
    • 基本数据类型:复制具体的值。
    • 引用数据类型创建一个新的对象,并复制原对象中该引用指向的具体内容。
    • 结果: 新对象和原对象在堆内存中完全独立。修改新对象,不会影响原对象

2. 如何实现深拷贝?

面试中常问“有哪些方法可以实现深拷贝”,主要有以下三种常见方式:

  • 重写 clone 方法,序列化与反序列化,json化再返 json 化
  1. 重写 clone() 方法(比较麻烦):
    • 实现 Cloneable 接口。
    • 重写 clone() 方法。在方法内部,不仅要调用 super.clone(),还需要手动对类中的每一个引用类型的成员变量再次调用 clone()
    • 缺点: 代码繁琐,如果对象嵌套层级很深,代码会非常难写。
  2. 使用序列化 (Serialization)(推荐,最常用):
    • 将对象序列化为字节流(Write),再反序列化为新对象(Read)。
    • 可以使用 Java 原生的 ObjectOutputStream / ObjectInputStream,要求对象实现 Serializable 接口。
    • 原理: 序列化会把对象及其引用的所有对象都转成二进制流,重新生成时自然是全新的对象。
    • 缺点: 性能相对较差。
  3. 使用第三方库(实际开发中最常用):
    • JSON 转换: 先把对象转成 JSON 字符串,再转回对象(如使用 Jackson, Gson, FastJson)。
      • MyObject copy = JSON.parseObject(JSON.toJSONString(original), MyObject.class);
    • 工具类: 如 Apache Commons Lang 的 SerializationUtils.clone()

3. final 关键字 (不可变性)

一句话总结: final 代表“最终的”、“不可更改的”。它可以修饰变量、方法和类

核心作用域与区别:

  1. 修饰变量 (最常考):
    • 基本数据类型(如 int, double):数值一旦初始化,就不能被修改(常量)。
    • 引用数据类型(如 Object, List):引用地址不可变,但对象内部的数据可以改变
      • 话术示例: “比如 final List list = new ArrayList();,我不能让 list 指向另一个新的 ArrayList,但我可以调用 list.add() 往里面加数据。”
  2. 修饰方法:
    • 该方法不能被子类重写 (Override)
    • 注意: private 方法隐式地被指定为 final,因为子类无法访问它,自然也无法重写。
  3. 修饰类:
    • 该类不能被继承
    • 典型例子: String 类就是 final 的,主要是为了保证字符串的不可变性和安全性。

4. * static 关键字 (类级别/静态)(比任何构造方法(new)都要早执行)

静态变量在堆中的 Class 对象中,而不在常量池中。

一句话总结: static 表示“静态的”,意味着成员属于类本身,而不是属于某个具体的对象实例。它先于对象存在。

核心作用域与特性:

  1. 静态变量 (Static Variable):
    • 被所有对象共享,在内存中只有一份副本。
    • 当类被加载时初始化。
  2. 静态方法 (Static Method):
    • 可以直接通过 类名.方法名 调用,不需要创建对象。
    • 重要限制: 静态方法中不能使用 thissuper 关键字,也不能直接访问非静态的成员变量或方法。(原因:静态方法加载时,对象可能还没创建)。
  3. 静态代码块 (Static Block):
    • static { ... }
    • 类加载时执行,且只执行一次。通常用于初始化静态资源。
  4. 静态内部类 (Static Inner Class):
    • 不需要依赖外部类的实例即可创建。
    • 只能访问外部类的静态成员。

5. 面试高频考察点:执行顺序

面试官经常会给一段代码,让你判断 static 代码块、构造代码块和构造方法的执行顺序。 口诀: 父类早于子类,静态早于非静态,代码块早于构造方法。 详细执行流程:

  1. 父类 静态代码块 (类加载时,只一次)
  2. 子类 静态代码块 (类加载时,只一次)
  3. 父类 非静态代码块 (每次 new 时)
  4. 父类 构造方法
  5. 子类 非静态代码块 (每次 new 时)
  6. 子类 构造方法