社招又来学习 Java 啦,这次选了何昊老师的程序员面试笔记作为主要资料,记录一下一些学习过程。
1.1 Java 程序初始化
Java 程序初始化遵循规则:静态变量优于动态变量;父类优于子类;成员变量的定义顺序;
具体体现为:父类静态变量 -> 父类静态代码块 -> 子类静态变量 -> 子类静态代码 -> 父类非静态变量 -> 父类非静态代码块 -> 父类构造方法 -> 子类非静态变量 -> 子类非静态代码块 -> 子类构造方法。
1.2 构造方法
- 每个类可以有多个构造方法,当没有提供时,编译器在将源代码编译为字节码的时候会提供一个默认的没有参数的构造方法。
- 仅在对象实例化时调用,不可显示调用。
- 不可以被继承,也就无法被重写。但可以被重载:重写(Override)是指子类有一个方法与其父类中的某个方法具有相同的方法名、返回类型和参数列表。然而,构造方法不能被重写,因为它们没有返回类型,并且其名称必须与类名相同,这使得子类无法声明一个与父类构造方法签名相同的方法。Java设计者选择不允许构造方法被继承或重写,主要是为了避免构造过程中的复杂性和潜在的错误。构造方法的调用必须明确无误,以确保对象在使用前被正确初始化。
- 子类可以通过 super 关键字显式调用父类的构造方法;实例化对象时,首先会调用父类的构造方法再执行子类的构造方法;
1.3 clone 方法的作用
Java 在处理基本数据类型时采用值传递的方式,其他类型都是按引用传递。clone 提供从某个已有的对象创造出一个和此对象相同状态的对象的方法。
clone 的类继承 cloneable 接口(实际无任何接口方法,仅为标识),重写 Object 类中的 clone 方法,在 clone 方法里调用 super.clone()(最终都会调用到 object 的 clone 方法,这个方法返回 object 对象的一个拷贝),最终将浅拷贝的引用指向对象新的克隆体。
默认的 clone 方法仅提供了浅克隆,实现深克隆通常比实现浅克隆更复杂,因为深克隆需要递归地复制对象的所有引用对象。以下是实现深克隆的一些方法:
-
重写
clone()
方法:如果你的类中的对象引用了其他对象,并且你想要复制这些对象,你需要重写clone()
方法,并在这个方法中确保所有引用的对象也被复制。 -
使用序列化:一种实现深克隆的简单方式是使用对象序列化机制。通过将对象序列化到一个字节数组,然后再从该字节数组反序列化,可以创建对象的一个完整副本。
-
复制构造函数:创建一个复制构造函数,它接受一个原对象作为参数,并使用该对象的值来初始化新对象。这种方法需要确保所有引用的对象也通过复制构造函数被复制。
-
复制工厂方法:类似于复制构造函数,但使用一个静态方法来创建对象的副本。
-
使用Apache Commons Lang:如果你使用Apache Commons Lang库,可以使用
SerializationUtils.clone()
方法来实现深克隆。
在Java中,数组的克隆行为取决于数组的维度:
-
一维数组:当克隆一维数组时,会进行浅克隆。这意味着克隆操作会创建一个新的数组对象,但数组中的元素不会被克隆。如果数组元素是引用类型,那么克隆后的数组将引用与原始数组相同的对象。
-
多维数组:对于多维数组,克隆行为取决于每个维度的数组。每个维度的数组都是作为一个单独的一维数组来克隆的,因此每个维度的数组都是浅克隆的。这意味着,如果克隆一个二维数组,你会得到一个新的二维数组对象,但每个子数组仍然是原始子数组的引用。
如果你需要对数