学习前提
理解Java方法、参数和字段;能阅读构造器调用。
本课完成后你能做什么
用构造器和方法维护对象的不变条件。
先理解机制
类描述状态和行为,对象是类的具体实例。每个Progress对象都有独立done计数;如果把它声明为static,多个实例就会共享同一份计数。
private阻止调用者直接设置字段。构造器验证total,complete限制上界,因而所有公开操作都维持0<=done<=total。封装的价值在于维护规则,不是机械生成所有setter。
零总数的百分比需要产品定义。本例定义为0;计算中先转换为long再乘100,避免int乘法提前溢出。整数除法向零截断,本例非负数即向下取整。
可运行示例
使用JDK 21。将代码保存为Main.java,在独立练习目录执行 javac -encoding UTF-8 Main.java,再执行 java Main。每章独立运行,不把多个public Main类放进同一文件。
public class Main {
static class Progress {
private final int total;
private int done;
Progress(int total) {
if (total < 0) throw new IllegalArgumentException("negative total");
this.total = total;
}
void complete() { if (done < total) done++; }
int percent() { return total == 0 ? 0 : (int) ((long) done * 100 / total); }
}
public static void main(String[] args) {
Progress first = new Progress(4);
Progress second = new Progress(4);
first.complete();
System.out.println(first.percent() + " " + second.percent());
Progress empty = new Progress(0);
empty.complete();
System.out.println(empty.percent());
}
}
推演与验证
两个对象输出25和0,说明状态独立。总数为0时complete不增加计数,仍输出0。
常见错误与边界
该类没有线程同步,适用于本课单线程程序。final限制字段重新赋值,并不自动让任意对象深度不可变。
动手练习
对总数2连续调用complete三次,并验证负数构造失败。
参考解法与理由
第三次调用被上界条件挡住,结果100。new Progress(-1)抛出IllegalArgumentException;调用者应修正输入。