本文总结 Core Java 书中的:第 3 章 Java 的基本程序设计结构、第 4 章 对象与类、第 5 章 继承。
3 Java 的基本程序设计结构
3.3 数据类型
- Java 有 8 种基本类型(primitive type):4 种整型、2 种浮点类型、char、boolean
- Java 7 起可用下划线增强数字可读性:
1_000_000 - 浮点数不适用于金融计算(二进制无法精确表示 1/10),应使用
BigDecimal
3.4 变量
$是合法字符,但仅用于编译器生成的名字,不要在代码中使用
3.6 字符串
- String 是不可变的(immutable)
- 不要用
==比较字符串:只有字符串常量是共享的,+或substring产生的结果不共享
3.10 数组
- 数组赋值是引用拷贝,两个变量指向同一数组:
int[] luckyNumbers = smallPrimes;
luckyNumbers[5] = 12; // smallPrimes[5] 也变成 12
- 值拷贝使用
Arrays.copyOf:
int[] copiedNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length);
彩票抽奖示例(从 1~n 中随机取 k 个不重复数字):
int[] harr = new int[n];
for (int i = 0; i < n; i++) {
harr[i] = i + 1;
}
int[] result = new int[k];
for (int i = 0; i < k; i++) {
int random = (int) (Math.random() * n);
result[i] = harr[random];
harr[random] = harr[n - 1]; // 用最后元素替换已取元素
n--;
}
Arrays.sort(result);
关键点:每次取的是下标而非值,通过缩小有效范围避免重复抽取。
4 对象与类
4.1 面向对象程序设计概述
| 关系 | 含义 | 示例 |
|---|---|---|
| 依赖 (uses-a) | 一个类的方法操纵另一个类的对象 | Order 使用 Account |
| 聚合 (has-a) | 类 A 的对象包含类 B 的对象 | Order 包含 Item |
| 继承 (is-a) | 类 A 扩展类 B | RushOrder 继承 Order |
设计原则:尽量减少类之间的依赖,降低耦合度。
4.2 使用预定义类
- 对象变量不是对象,只是对象的引用
Date deadline;只声明了变量,未引用任何对象new操作符返回的是引用- 可设置为
null表示不引用任何对象
4.3 用户自定义类
构造器特点:
- 与类同名、无返回值
- 可有多个(重载)
- 伴随
new调用
封装原则:
- 实例域用
private - 不要返回可变对象的引用,应返回 clone
// 错误:破坏封装
public Date getHireDay() {
return hireDay;
}
// 正确:返回副本
public Date getHireDay() {
return (Date) hireDay.clone();
}
关于 final:
- 适用于基本类型或不可变类
- 对可变对象,
final只保证引用不变,对象内容仍可修改:
private final Date hireDate; // 引用不可变,但 hireDate.setTime() 仍可调用
4.4 静态域与静态方法
- 静态域属于类,所有实例共享:
class Employee {
private static int nextId = 1; // 所有实例共享
private int id; // 每个实例独有
}
- 静态方法建议用类名调用:
Employee.getNextId() - 每个类可有
main方法用于单元测试
4.5 方法参数
Java 始终是按值调用:
- 不能修改基本类型参数
- 可以改变对象参数的状态
- 不能让对象参数引用新对象
常见误解:Java 对象采用引用传递?实际上不是。反例:
public static void swap(Employee x, Employee y) {
Employee temp = x;
x = y;
y = temp;
}
Employee a = new Employee("Alice", 70000);
Employee b = new Employee("Bob", 60000);
swap(a, b);
// 结果:a 仍是 Alice,b 仍是 Bob
原因:调用 swap 时,a 将引用的副本传给 x,b 将引用的副本传给 y。方法内交换的只是 x、y 的指向,方法外的 a、b 不受影响。
4.6 对象构造
- 方法签名 = 方法名 + 参数类型(不含返回类型)
- 无构造器时系统提供默认构造器(域设为默认值)
- 提供了构造器后,默认构造器不再自动生成
- 建议显式初始化实例域:
class Employee {
private String name = "";
private double salary = 0;
}
4.10 类设计技巧
- 保证数据私有
- 一定要初始化数据
- 不要过多使用基本类型,用类封装
- 不是所有域都需要 getter/setter
- 职责过多的类要分解
- 命名要体现职责
5 继承
5.1 类、超类和子类
this vs super:
super不是对象引用,只是调用超类的关键字- 两者调用构造器都必须是第一条语句,不能同时出现
多态与动态绑定:
- 多态:对象变量可指向多种实际类型
- 动态绑定:运行时自动选择调用哪个方法
数组协变的陷阱:
Manager[] managers = new Manager[10];
Employee[] staff = managers; // 合法,但危险
staff[0] = new Employee(...); // 编译通过,运行时出错
静态绑定 vs 动态绑定:
| 特性 | 静态绑定 | 动态绑定 |
|---|---|---|
| 时机 | 编译时 | 运行时 |
| 适用 | private/static/final 方法、构造器 | 虚方法(可重写的方法) |
| 依据 | 类信息 | 对象信息 |
| 对应 | 重载 (Overload) | 重写 (Override) |
方法表:虚拟机为每个类预先创建方法表,避免每次调用都搜索。
访问修饰符:
| 修饰符 | 可见范围 |
|---|---|
| private | 本类 |
| 默认 | 本包 |
| protected | 本包 + 所有子类 |
| public | 所有类 |
5.2 Object:所有类的超类
equals 方法标准模板:
public boolean equals(Object otherObject) {
// 1. 同一引用
if (this == otherObject) return true;
// 2. null 检查
if (otherObject == null) return false;
// 3. 类型检查(子类语义不同用 getClass,相同用 instanceof)
if (getClass() != otherObject.getClass()) return false;
// 4. 类型转换
Employee other = (Employee) otherObject;
// 5. 比较域(基本类型用 ==,对象用 equals)
return Objects.equals(name, other.name)
&& salary == other.salary
&& Objects.equals(hireDay, other.hireDay);
}