元数据卡
- 前置知识:第7章全三节(上/中)
- 预计时间:20 分钟
- 完成标志:能独立完成两道编程题,能说出常见陷阱的成因
常见陷阱
陷阱一:两个变量指向同一个对象
java
Book b1 = new Book("Java 核心技术", "Horstmann", 99);
Book b2 = b1; // ⚠️ 不是复制对象,是复制引用!
b2.setTitle("不同书名");
System.out.println(b1.getTitle()); // "不同书名"——b1 也变了原因:
b1和b2指向堆里同一个对象。解决方案:写拷贝构造方法Book(Book other) { this(other.title, other.author, other.price); },然后new Book(b1)。
陷阱二:Java 是值传递
java
static void changeTitle(Book b) {
b.setTitle("新书名"); // ✅ 通过地址副本修改了同一个对象
b = new Book("另一本", "某", 50); // ❌ 新地址只影响本地副本
}核心:Java 永远传值的副本。基本类型传数值,引用类型传地址副本。改"引用指向的对象"能影响外部,改"引用本身"不能。
陷阱三:构造方法里别调用可重写的方法
java
class Parent {
Parent() { print(); } // ⚠️ 危险
void print() { System.out.println("Parent"); }
}
class Child extends Parent {
String value = "Hello";
@Override void print() { System.out.println(value.length()); }
}
new Child(); // NullPointerException——Child 的 value 还没初始化!教训:极其难调试。构造方法中不要调用被子类重写的方法。
陷阱四:getter 暴露内部可变对象
java
public List<String> getCourses() { return courses; } // ⚠️ 外部能改内部列表安全做法:
return Collections.unmodifiableList(courses)或return new ArrayList<>(courses)。
热身练习(10 分钟,必做)
1. 定义 Student 类——private 字段 name、age、score,带校验的构造方法与 getter/setter。
java
public class Student {
private String name;
private int age;
private double score;
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
if (score < 0 || score > 100)
throw new IllegalArgumentException("成绩必须 0-100");
this.score = score;
}
// getter/setter 省略...
}2. 在 main 中创建三个 Student 对象,存数组,遍历算平均分。
3. 加 static 字段 count 跟踪创建总数。
挑战练习(20 分钟,选做)
BankAccount 类:
java
public class BankAccount {
private String accountNumber; // 不可修改
private String ownerName;
private double balance; // 余额不能为负
public BankAccount(String accountNumber, String ownerName, double initialDeposit) {
if (accountNumber == null || accountNumber.isEmpty())
throw new IllegalArgumentException("账号不能为空");
if (initialDeposit < 0)
throw new IllegalArgumentException("初始存款不能为负");
this.accountNumber = accountNumber;
this.ownerName = ownerName;
this.balance = initialDeposit;
}
// getters——所有字段
public String getAccountNumber() { return accountNumber; }
public String getOwnerName() { return ownerName; }
public double getBalance() { return balance; }
// 没有 setAccountNumber / setBalance——账号不可改,余额靠 deposit/withdraw
public void deposit(double amount) {
if (amount <= 0) throw new IllegalArgumentException("存款金额必须 > 0");
balance += amount;
}
public boolean withdraw(double amount) {
if (amount <= 0) return false;
if (amount > balance) return false;
balance -= amount;
return true;
}
public void transfer(BankAccount target, double amount) {
if (withdraw(amount)) target.deposit(amount);
}
}测试:创建两个账户,存钱、取钱、转账、尝试透支。
旅人笔记
类 = 蓝图,对象 = 实例。构造方法 = 降生洗礼。this = 指向自己。static = 属于类的全体共享。private = 藏起来,public 方法 = 安全的门。getter/setter = 带校验的读写口。package = 命名空间。
这段旅程最难的不是语法——是从"写一段代码"到"定义一个类型"的思维转变。
验收标准
- [ ] 说清类(蓝图)和对象(实例)的区别
- [ ] 会写 private 字段 + public getter/setter
- [ ] 会写带校验的构造方法,理解无参构造何时消失
- [ ] 会用 this 区分字段和参数
- [ ] 理解 static 属于类本身,static 方法不能访问实例成员
- [ ] 理解 Java 值传递——引用复制不复制对象
- [ ] 知道 private/默认/protected/public 的可见范围
下一步
现实世界不是一座孤岛——Student 是 Person 的一种。类之间的继承、组合、多态将在下一章展开。
下一章:继承与多态 → ch08-inheritance-polymorphism.md