第13篇:JDK和JRE、final与static、堆和栈

📌 系列导航《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第12篇:Java对象、类、抽象类、构造函数 |
➡️ 下一篇:第14篇:Java final关键字详解

一、核心知识点

  • JDK / JRE / JVM 三者关系(包含与被包含)
  • static:静态变量、静态方法、静态代码块
  • final:修饰类、方法、变量(不可变)
  • 堆(Heap)与栈(Stack)内存区域区别
  • GET 与 POST 基础区别(Web部分简要)

二、通俗讲解(1分钟开心学)

1. JDK、JRE、JVM 三兄弟

  • JDK(Java Development Kit):Java开发工具包。包含JRE + 编译工具javac + 其他工具。给开发者用。
  • JRE(Java Runtime Environment):Java运行环境。包含JVM + 核心类库。给普通用户运行Java程序用。
  • JVM(Java Virtual Machine):Java虚拟机。运行字节码的核心。是跨平台的关键。

包含关系:JDK ⊃ JRE ⊃ JVM。

生活类比
JVM是发动机,JRE是发动机+轮子+座椅(能跑的基础),JDK是整车+修理工具箱(能开发)。

2. static:属于类,不属于对象

  • 静态变量:所有对象共享一份。类加载时初始化。
  • 静态方法:可以直接类名调用,不能访问非静态成员(因为还没有对象)。
  • 静态代码块:类加载时执行一次,常用于初始化静态资源。

3. final:最终的,不可改变

  • final修饰类:不能被继承。
  • final修饰方法:不能被重写。
  • final修饰变量:只能赋值一次(基本类型值不变,引用类型引用地址不变,但对象内部可变)。

4. 堆和栈

  • 栈(Stack):每个线程私有,存储局部变量、方法调用参数、对象引用。方法结束自动释放。速度快。
  • 堆(Heap):所有线程共享,存储所有new出来的对象和数组。GC管理回收。

内存示意图

Person p = new Person();
// p(引用变量)在栈,new Person()对象在堆

三、实操代码案例 + 场景说明

场景:统计某个类被创建了多少个对象,并保证某个常量不被修改。

public class StaticFinalDemo {
    public static final double PI = 3.14159;  // 静态常量
    
    private static int instanceCount = 0;    // 静态变量,共享计数
    
    public StaticFinalDemo() {
        instanceCount++;
    }
    
    public static int getInstanceCount() {   // 静态方法
        return instanceCount;
    }
    
    static {
        System.out.println("静态代码块:类加载时执行一次");
    }
    
    public static void main(String[] args) {
        new StaticFinalDemo();
        new StaticFinalDemo();
        System.out.println("创建对象数:" + StaticFinalDemo.getInstanceCount());
        
        // PI = 3.14;  // 编译错误,final变量不能重新赋值
    }
}

堆栈示例

public class HeapStackDemo {
    int instanceVar = 10;  // 在堆中(属于对象)
    
    public void method() {
        int localVar = 20;  // 在栈中
        Person p = new Person();  // p引用在栈,对象在堆
    }
}

GET和POST简要区别

  • GET:参数在URL上,长度有限,不安全(明文),可缓存。
  • POST:参数在请求体,理论上无长度限制,相对安全,不可缓存。

四、避坑要点

错误/误区 后果 正确做法
静态方法中想用this 编译错误 静态方法中不能使用this
静态变量多线程环境下不加修改 线程安全问题 使用synchronizedAtomicInteger
认为final引用变量内部状态也不可变 错误理解,对象内部仍然可变 需要不可变对象时才用不可变类
递归调用过深导致栈溢出 StackOverflowError 改为迭代或增加栈大小(有限)
new大量对象不释放导致堆溢出 OutOfMemoryError 及时解除引用,让GC回收

五、面试高频考点

Q1:JDK、JRE、JVM 的关系?

JDK包含JRE,JRE包含JVM。JDK > JRE > JVM。JDK用于开发,JRE用于运行,JVM是运行字节码的核心。

Q2:静态变量和实例变量的区别?

静态变量属于类,类加载时初始化,所有实例共享一份。实例变量属于对象,每次new都会重新初始化,每个实例独立。

Q3:堆和栈分别存储什么?

栈存储局部变量、基本类型值、对象引用、方法调用帧;堆存储所有对象实例和数组。

六、练习题

  1. 设计:编写一个Counter类,统计该类被实例化的次数,并提供静态方法获取次数。
  2. 代码改错final StringBuilder sb = new StringBuilder("a"); sb = new StringBuilder("b"); 是否正确?为什么?
  3. 内存分析:画出代码int a=5; String s = new String("hi");执行时的堆栈内存图。

📊 你的学习进度

  • 当前:第13篇 / 共44篇 · 第二阶段:核心语法与面向对象(第5~20篇)
  • ✅ 已完成:第1~12篇
  • 📖 正在学:第13篇
  • ⏳ 待学习:第14~44篇

👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇

💡 本专栏每篇都包含:避坑表 + 面试高频考点 + 练习题。每天30分钟,100天拿offer!


👉 下一篇预告

《Java final关键字详解》

内容简介:final修饰类、方法、变量的详细规则,空白final用法,String为什么是final的。

💡 学完这篇,你将彻底掌握final的语义,面试再问“final、finally、finalize区别”轻松回答。

📌 《Java 100 天进阶之路 | 从入门到上岗就业》 每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐