1. Java入门第六天:面向对象基础与类设计
我清楚地记得自己刚开始接触Java面向对象概念时的困惑。那天早上,我盯着"类"和"对象"这两个词看了足足十分钟,直到把咖啡喝完才突然开窍——类就像建筑设计图,而对象就是按这张图建造出来的实际房子。这个简单的类比让我瞬间理解了面向对象编程(OOP)的核心思想。
1.1 类的定义与实例化
在Java中定义类就像在现实世界中定义一种新的数据类型。我习惯用这个模板开始每个类的编写:
java复制public class BankAccount {
// 字段(属性)
private String accountNumber;
private double balance;
// 构造方法
public BankAccount(String accountNumber) {
this.accountNumber = accountNumber;
this.balance = 0.0;
}
// 方法(行为)
public void deposit(double amount) {
if(amount > 0) {
balance += amount;
}
}
public double getBalance() {
return balance;
}
}
这里有个初学者常犯的错误:在类中直接写执行逻辑。实际上,类应该只包含定义,真正的操作是在main方法中通过创建对象来完成的:
java复制public class Main {
public static void main(String[] args) {
BankAccount myAccount = new BankAccount("123456789");
myAccount.deposit(1000);
System.out.println("当前余额: " + myAccount.getBalance());
}
}
1.2 封装原则的实际应用
封装是OOP三大特性中最容易被忽视的一个。我见过太多人为了图方便把字段设为public,这就像把银行金库大门敞开一样危险。正确的做法是:
- 所有字段设为private
- 通过getter/setter方法控制访问
- 在方法中添加业务逻辑验证
比如改进版的BankAccount:
java复制public void withdraw(double amount) {
if(amount <= 0) {
throw new IllegalArgumentException("取款金额必须为正数");
}
if(amount > balance) {
throw new IllegalStateException("余额不足");
}
balance -= amount;
}
这个简单的改动就能避免90%的非法操作。记住:好的封装就像严格的安检系统,把问题挡在门外比事后处理要高效得多。
2. Java入门第七天:继承与多态的实战技巧
第七天的学习让我真正体会到Java的强大之处。继承不是简单的代码复用,而是建立类型体系的基石。我设计了一个支付系统的例子来说明这点:
2.1 继承关系的正确使用
java复制class Payment {
protected double amount;
public Payment(double amount) {
this.amount = amount;
}
public void process() {
System.out.println("处理基础支付: " + amount);
}
}
class CreditCardPayment extends Payment {
private String cardNumber;
public CreditCardPayment(double amount, String cardNumber) {
super(amount);
this.cardNumber = cardNumber;
}
@Override
public void process() {
System.out.println("处理信用卡支付: " + amount + " 卡号: " + maskCardNumber());
}
private String maskCardNumber() {
return "****-****-****-" + cardNumber.substring(12);
}
}
这里有几个关键点:
- 使用protected修饰符允许子类访问父类字段
- 使用@Override注解明确表示方法重写
- 子类可以扩展新的属性和方法
- 子类可以重写父类方法改变行为
2.2 多态的实际威力
多态最神奇的地方在于:父类引用可以指向子类对象。这在实际项目中极为有用:
java复制public class PaymentProcessor {
public static void main(String[] args) {
Payment[] payments = new Payment[2];
payments[0] = new Payment(100);
payments[1] = new CreditCardPayment(200, "1234567890123456");
for(Payment p : payments) {
p.process(); // 自动调用实际类型的process方法
}
}
}
输出结果:
code复制处理基础支付: 100.0
处理信用卡支付: 200.0 卡号: ****-****-****-3456
这种设计让系统扩展变得非常容易——新增支付类型只需继承Payment类,无需修改现有处理逻辑。
3. Java入门第八天:接口与抽象类的抉择
第八天的学习让我明白了Java设计中的灵活性。接口和抽象类看似相似,实则各有适用场景。
3.1 接口的本质与使用
接口定义行为契约,这是我学习时整理的对比表:
| 特性 | Java 8之前接口 | Java 8+接口 |
|---|---|---|
| 方法实现 | 不允许 | 允许default/static方法实现 |
| 字段 | 只能是public static final常量 | 同前 |
| 多重继承 | 一个类可实现多个接口 | 同前 |
| 设计目的 | 定义行为规范 | 增加代码复用能力 |
实际案例:
java复制interface Loggable {
default String getLogHeader() {
return "[" + LocalDateTime.now() + "]";
}
void log(String message);
}
class FileLogger implements Loggable {
@Override
public void log(String message) {
System.out.println(getLogHeader() + " 文件日志: " + message);
}
}
3.2 抽象类的适用场景
抽象类适合定义部分实现的模板。我总结的选用原则:
- 需要共享代码时用抽象类
- 需要定义多种行为契约时用接口
- 考虑未来扩展性:接口更灵活
- Java 8后,两者界限已模糊,根据团队规范选择
示例:
java复制abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
// 抽象方法,子类必须实现
public abstract void makeSound();
// 具体方法,子类可直接使用
public void eat() {
System.out.println(name + "正在进食");
}
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + ": 汪汪!");
}
}
4. 综合实战:小型银行系统设计
经过三天的学习,我尝试设计了一个简单的银行系统来整合所有概念:
4.1 类结构设计
java复制// 账户基类
abstract class Account {
protected String accountId;
protected double balance;
public Account(String accountId) {
this.accountId = accountId;
}
public abstract void deposit(double amount);
public abstract void withdraw(double amount);
public double getBalance() {
return balance;
}
}
// 储蓄账户
class SavingsAccount extends Account implements InterestBearing {
private double interestRate;
public SavingsAccount(String accountId, double interestRate) {
super(accountId);
this.interestRate = interestRate;
}
@Override
public void deposit(double amount) {
if(amount <= 0) throw new IllegalArgumentException("存款金额必须为正");
balance += amount;
}
@Override
public void withdraw(double amount) {
if(amount <= 0) throw new IllegalArgumentException("取款金额必须为正");
if(amount > balance) throw new IllegalStateException("余额不足");
balance -= amount;
}
@Override
public void applyInterest() {
balance *= (1 + interestRate);
}
}
// 利息计算接口
interface InterestBearing {
void applyInterest();
}
4.2 系统测试与验证
java复制public class BankSystem {
public static void main(String[] args) {
Account[] accounts = new Account[2];
accounts[0] = new SavingsAccount("SA001", 0.05);
accounts[1] = new CheckingAccount("CA001", 1000);
// 多态处理
for(Account acc : accounts) {
acc.deposit(500);
if(acc instanceof InterestBearing) {
((InterestBearing)acc).applyInterest();
}
System.out.println(acc.getClass().getSimpleName()
+ " 余额: " + acc.getBalance());
}
}
}
这个案例融合了:
- 抽象类定义通用行为
- 具体类实现特定逻辑
- 接口扩展额外功能
- 多态处理不同类型对象
- 类型检查与强制转换
在实际编码中,我发现几个关键点:
- 合理使用protected可见性
- 方法重写时要保持行为一致性
- 接口默认方法可以大大减少重复代码
- instanceof检查应该作为最后手段
这三天的学习让我深刻体会到,Java的面向对象特性不是孤立的语法点,而是相互配合的工具集。正确的设计应该像搭积木一样,用简单的概念组合出复杂的系统。
