- xianaldai2026-08-1210677
本期是Java开发教程系列的第五期,本期主要向各位介绍*封装*和
static静态成员——把数据保护起来,并认识"属于类而不属于对象"的成员.若你已经熟悉 getter/setter 和 static,可以跳过本期内容.*每期叠甲*:
时间仓促,水平有限,文中难免存在缺点和错误,恳请广大开发者和从业者指正.
*一、封装:private + getter/setter*
第 4 期学了
private——只有本类内部能访问.但光把字段设为 private 还不够,外面*完全读不到*也不行.封装的典型写法是:*字段私有,再用公开的方法来读写*```public class Student {
private String name; // 字段私有
private double score;
public Student(String name, double score) {
this.name = name;
this.score = score;
}
// getter:读值
public String getName() {
return name;
}
public double getScore() {
return score;
}
// setter:改值,可以在里面做校验
public void setScore(double score) {
if (score < 0) {
System.out.println("成绩不能为负数,拒绝修改");
return; // 直接结束方法,不修改
}
this.score = score;
}
}
``现在外面不能直接写s.score = -80了(编译报错),只能通过setScore()改——而setScore()` 里拦住了负数.数据就安全了.*命名约定*:字段叫
score,getter 叫getScore(),setter 叫setScore();boolean 字段的 getter 叫isXxx().这个约定 IDE 可以一键生成.*为什么说封装是好事*:
- *能校验*:setter 里可以拦非法值,像上面的负数成绩
- *能改内部实现*:字段将来换存储方式,只要 getter/setter 签名不变,外面代码不用动
- *缩小影响面*:别人只依赖你公开的方法,内部怎么改都不怕
*二、static 静态成员*
static修饰的成员属于*类*而不是某个对象.看例子:```public class Student {
public static String school = "第一中学"; // 静态字段
public String name; // 实例字段
public static void welcome() { // 静态方法
System.out.println("欢迎来到 " + school);
}
}
``- ****静态字段****:所有对象****共享同一份****.改Student.school = "第二中学"`,所有学生的 school 一起变- *实例字段*:每个对象各有一份.
s1.name和s2.name互不影响- *静态方法*:用*类名直接调*,不用创建对象:```
Student.welcome(); // 直接调,不需要 new
```- 静态方法里*不能直接用非静态的字段和方法*(因为没有"某个对象"可指);反过来,非静态方法可以用静态成员什么时候用
static:- *工具方法*:像
Math.abs(),做一件和任何对象都无关的事- *常量*:
public static final一起用,表示一个不变的全局值- *共享状态*:像上面的
school,所有对象要共用现在你回头看
System.out.println(...):System是一个类,out是它一个public static的字段——因为静态,不用创建对象,直接用System.out就能拿到.*static 与内存:静态成员不参与垃圾回收*
讲完用法,还得说一个和内存有关的注意事项——
static字段*不会被垃圾回收*.回忆一下:实例字段是跟着对象走的,对象没人用了,整个对象(连同它的实例字段)会被垃圾回收(垃圾回收是 JVM 自动做的事:没人再用的对象,占的内存会被收回去,这个机制后面我们会专门学).但静态字段属于*类*,而类从*加载进 JVM 的那一刻起就一直活着*,直到程序结束.所以:
- 静态字段的引用一直存在 → 垃圾回收器认为它引用的对象"还在被使用" → *永远不回收*
- 实例字段的对象没人用了 → 引用断开 → 正常回收
这不一定是坏事(常量本来就该常驻),但有一个经典坑:*把会无限增长的东西放进 static 集合*:```
public class GlobalData {
// 全程序共享的日志列表,每来一条就 add 一条,只增不减
public static List<String> logs = new ArrayList<>();
}
```logs是 static,垃圾回收器永远认为它"还在用"——里面的每一条日志都回收不掉.运行一天两天看不出来,运行几个月,这个 List 越来越大,内存被悄悄吃掉,程序越来越慢.这就是最常见的*内存泄漏*之一:对象没用了却回收不掉.三条使用建议:
- *static 放常量*(
public static final的数值、字符串)没问题:值小、数量固定,常驻内存也合理- *static 集合要当心*:要么限制大小(满了清旧的),要么别用 static 装会增长的数据
- *static 大对象*(大数组、大缓存)动手前先问一句:它真的需要活到程序结束吗?不需要,就别用 static
*三、小项目:受保护的成绩*
把封装和 static 串起来,做一个带校验的成绩管理.
文件一
Student.java:```public class Student {
private String name;
private double score;
// 静态字段:所有学生共享
public static String school = "第一中学";
public Student(String name, double score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public double getScore() {
return score;
}
// setter:带校验,成绩不能为负
public void setScore(double score) {
if (score < 0) {
System.out.println(name + " 的成绩不能为负数,拒绝修改");
return;
}
this.score = score;
}
}
``文件二Main.java:``public class Main {
public static void main(String\[\] args) {
Student s1 = new Student("小明", 92);
Student s2 = new Student("小红", 58);
// 直接改私有字段会编译报错: s1.score = -10;
s1.setScore(-10); // 走 setter,被校验拦下
s1.setScore(95); // 合法,修改成功
System.out.println(s1.getName() + ":" + s1.getScore());
System.out.println(s2.getName() + ":" + s2.getScore());
// 静态字段通过类名访问,所有对象共享
System.out.println("学校:" + Student.school);
Student.school = "第二中学"; // 改一处,全部对象一起变
System.out.println(s1.getName() + " 的学校:" + Student.school);
System.out.println(s2.getName() + " 的学校:" + Student.school);
}
}
``运行结果:``小明 的成绩不能为负数,拒绝修改
小明:95.0
小红:58.0
学校:第一中学
小明 的学校:第二中学
小红 的学校:第二中学
``重点看两处:负数成绩被 setter 拦下;Student.school` 改一次,两个学生对象读到的学校一起变——静态字段就是"所有对象共享同一份".*朝花夕拾:System.out 背后的 static*
从第 1 期到现在,我们写了无数遍
System.out.println(...),它到底怎么工作的?学完static,终于能拆开:-
System是java.lang包里的一个类-
out是它内部的一个public static字段,类型是PrintStream(一个负责输出的类)- 因为是
static,不需要new System(),直接用System.out就能拿到那个输出对象-
.println(...)则是这个输出对象的方法一行天天写的代码,背后是"静态字段 + 对象方法"的组合——这正是本期学的概念.另外,第 3 期说过
java.lang自动导入,System就是java.lang里的类,所以从第 1 期起我们写它从来没写过 import.*总结*
本期完成了"把数据管起来"的关键一步:
- *封装*:
private字段 + getter/setter,setter 里做校验;命名约定getXxx/setXxx/isXxx\- *static*:属于类不属于对象;静态方法用类名直接调,静态字段所有对象共享;静态方法里不能直接用非静态成员;*静态字段不参与垃圾回收,慎放会增长的数据*
- 回头看
System.out,静态的活教材接下来我们学习*继承与多态*——让类之间可以"父子相传",开始真正发挥面向对象的威力.
主楼 - ryuki2026-08-1220480
佬不睡觉的么,大半夜更教程,超人来的
- xianaldai2026-08-1210677
这何尝不是熬夜流coding爱好者