《Java 100 天进阶之路》第33篇:Java中的static关键字详解
第33篇:Java中的static关键字详解
📌系列导航:《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第32篇:Java常用工具类(Objects、Collections、Arrays深入) |
➡️ 下一篇:第34篇:Java序列化与反序列化详解
一、核心知识点
- 静态变量(类变量):所有实例共享,类加载时初始化
- 静态方法(类方法):只能访问静态成员,可直接类名调用
- 静态代码块:类加载时执行一次,用于初始化静态资源
- static 在 JVM 中的内存分配(方法区 / 元空间)
- 静态导入(
import static)
二、通俗讲解(1分钟开心学)
1. static 的含义
static表示“属于类而不是实例”。被 static 修饰的成员随着类加载而存在,不需要创建对象即可访问。
2. 静态变量(类变量)
所有对象共享一份数据。常用于计数、单例模式中的 instance、配置常量等。
3. 静态方法(类方法)
工具类中常用,比如Math.sqrt()、Collections.sort()。静态方法中不能直接使用this和非静态成员(因为可能还没有对象)。
4. 静态代码块
在类加载时自动执行一次,常用于加载驱动、初始化静态资源等。可以多个,按顺序执行。
5. 静态导入
import static java.lang.Math.PI;可以直接写PI而不需要Math.PI,但滥用会降低可读性。
6. 内存位置
静态变量存储在方法区(JDK8 以后叫元空间),而不是堆中。
生活类比:
静态变量就像公司里的“公告栏”,所有人都能看到同一份内容,修改后所有人都看到变化。
实例变量就像每个人自己的工位,每个人有自己的物品。
三、实操代码案例 + 场景说明
场景:统计某个类被创建了多少个对象,并提供一个工具方法。
publicclassStaticDemo{// 静态变量:所有实例共享,计数privatestaticintinstanceCount=0;// 静态常量publicstaticfinaldoublePI=3.14159;// 实例变量privateStringname;publicStaticDemo(Stringname){this.name=name;instanceCount++;// 每创建一次,计数+1}// 静态方法:获取创建了多少个实例publicstaticintgetInstanceCount(){returninstanceCount;}// 静态代码块:类加载时执行一次static{System.out.println("类 StaticDemo 被加载,执行静态代码块");// 可以在这里加载配置、驱动等}// 实例方法publicvoidshow(){System.out.println("实例:"+name);}publicstaticvoidmain(String[]args){newStaticDemo("A");newStaticDemo("B");System.out.println("总共创建了 "+StaticDemo.getInstanceCount()+" 个对象");System.out.println("圆周率:"+StaticDemo.PI);}}// 静态导入示例importstaticjava.lang.System.out;importstaticjava.lang.Math.*;publicclassStaticImportDemo{publicstaticvoidmain(String[]args){out.println("Hello");// 直接写 out,省略 System.doubleresult=sqrt(pow(3,2)+pow(4,2));// 不用 Math.out.println("斜边长:"+result);}}四、避坑要点
| 错误/误区 | 后果 | 正确做法 |
|---|---|---|
静态方法中尝试使用this | 编译错误 | 静态方法中不能使用this |
| 静态变量多线程环境下不加同步 | 计数不准、线程安全问题 | 使用synchronized或AtomicInteger |
| 误以为静态代码块可以抛出非运行时异常而不处理 | 编译错误 | 用 try-catch 包裹 |
| 静态方法被子类重写(其实不能,只能隐藏) | 调用时还是父类的实现 | 理解:静态方法没有多态,调用看引用类型 |
五、面试高频考点
Q1:static 变量和方法的内存分配在哪?
在方法区(JDK8 前永久代,JDK8+ 元空间),随类加载而分配,类卸载而释放。
Q2:静态代码块和实例代码块的区别?
静态代码块在类加载时执行一次;实例代码块在每次创建对象时执行,且优先于构造方法。
Q3:能否在静态方法中访问非静态变量?为什么?
不能,因为非静态变量属于具体对象,静态方法调用时可能还没有任何对象存在。
六、练习题
- 设计:编写一个
Logger类,包含一个静态方法log(String msg),每次调用时打印时间戳和消息,并统计调用次数。 - 代码分析:写出以下代码的输出。
classTest{static{System.out.print("A ");}{System.out.print("B ");}Test(){System.out.print("C ");}}publicclassMain{publicstaticvoidmain(String[]args){newTest();newTest();}} - 动手:使用静态导入简化
System.out.println和Math.sqrt的调用,写一个小程序。
📊 你的学习进度
- 当前:第33篇 / 共44篇 ·第五阶段:工具类、异常最佳实践、序列化(第32~35篇)
- ✅ 已完成:第1~32篇
- 📖 正在学:第33篇
- ⏳ 待学习:第34~44篇
👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇
💡 本专栏每篇都包含:避坑表 + 面试高频考点 + 练习题。每天30分钟,100天拿offer!
👉 下一篇文章预告
《第34篇:Java序列化与反序列化详解》
内容简介:Serializable接口、transient关键字、serialVersionUID的作用、反序列化安全风险。
💡 学完这篇,你将掌握对象的持久化存储,面试再问serialVersionUID轻松回答。
📌《Java 100 天进阶之路 | 从入门到上岗就业》每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!
📌 除了Java,我也在深挖智能物流实战(出版社WMS、托盘调度、机器学习落地)。如果你对技术在不同领域的实战感兴趣,欢迎点击我的头像,看看专栏《出版社物流WMS智能调度实战》。技术相通,思路可鉴。
