实例变量、静态变量、局部变量的生命周期

文章目录

前言

本篇内容出自《Java面向对象编程:孙卫琴》第三章部分内容,目的是带你搞懂实例变量、静态变量、局部变量生命周期概念

一、静态变量和实例变量的生命周期

类的成员变量有两种:一种是被static关键字修饰的变量,叫类变量,或者静态变量,没有被static修饰的,叫实例变量

静态变量与实例变量的区别在于:

  • 类的静态变量在内存中只有一个,Java虚拟机在加载类的过程中为静态变量分配内存,静态变量位于方法区,被类的所有实例共享。静态变量可以直接通过类名被访问。静态变量的生命周期取决于类的生命周期,当加载类的时候,静态变量被创建并分配内存,当卸载类的时候,静态变量被销毁并撤销内存。
  • 类的每个实例都有相应的实例变量。每创建一个类的实例,Java虚拟机就会为实例变量分配一次内存,实例变量位于堆区中。实例变量的生命周期取决于实例的生命周期,当创建实例的时候,实例变量被创建并分配内存,当销毁实例的时候,实例变量被销毁并撤销内存。

以下Counter类有两个成员变量,其中count1变量为实例变量,而count2变量为静态变量:

public class Counter { 
    public int count1 = 0;  //count1 实例变量 
    public static int count2 = 0;  //count2 静态变量
}

以下代码创建了两个Counter实例,然后分别修改它们的count1和count2变量:

	Counter counterA = new Counter();
    Counter counterB = new Counter();
    counterA.count1++;
    counterA.count2++;
    counterB.count1++;
    counterB.count2++;

执行以上代码后,Java虚拟机的运行时数据区如图所示:
《实例变量、静态变量、局部变量的生命周期》
从图中我们就可以理解之前说的几个要点:

  1. 静态变量位于方法区,被类的所有实例共享。所以静态变量count2在内存中只有一个,执行counterA.count2++或counterB.count2++实际上操纵的都是Counter类的同一个静态变量count2,即值为2;
  2. 实例变量位于堆区中。执行counterA.count1++实际上是由CounterA变量引用Counter实例的count1变量,和counterB引用的count1变量是不同的,所以各自的值都为1。

结合以前学过的基础知识,我们知道静态变量是可以直接通过 类名.变量 这种形式访问:

	counterA.count1++;  //通过counterA引用变量来访问count2变量
	Counter.count2++;  //通过Counter类名来访问count2变量

对于count1实例变量,是否可通Counter.count1(类名访问)访问呢?
答案显然是不行的,从图中我们看出,实例变量总是属于特定的实例的,Java虚拟机无法只通过类名就知道该访问到底是哪个实例中的变量。

二、局部变量的生命周期

什么是局部变量?
局部变量指的是在一个方法的内部或者方法的一个代码块中声明的变量,前者的作用域就是整个方法,后者的作用域则是这个代码块(代码块就是{}以内的代码)
《实例变量、静态变量、局部变量的生命周期》

大概了解了一下局部变量概念,让我们看看它的生命周期。
局部变量的生命周期取决于所属的方法何时被调用及结束调用!

  • 当Java虚拟机(更确切的说,是Java虚拟机中的某个线程)调用一个方法时,就会为这个方法中的局部变量分配内存。
  • 当Java虚拟机结束这一调用,同时就会结束这个方法中局部变量的生命周期。

通过下面的代码例子来进一步了解局部变量的生命周期:

public class Sample { 
    int var1 =1;  //var1是实例变量
    static int var2=2;  //var2是静态变量

    public int add(){ 
        int var3 = var1 +var2;  //var3是局部变量
        return var3;
    }

    public int delete(){ 
        int var4 = var1 - var2;  //var4是局部变量
        return var4;
    }

    public static void main(String[] args) { 
        new Sample().add();
    }
}

生命周期变化流程如下:
(1)加载Sample类,开始惊天变量var2的生命周期,var2位于方法区。
(2)创建Sample实例,开始实例变量var1的生命周期,var1位于堆区。
(3)调用Sample实例的add()方法,开始局部变量var3的生命周期,var3位于Java栈区
(4)执行完毕Sample实例的add()方法,结束局部变量var3的生命周期,退回到main()方法。
(5)执行完毕Sample类的main()方法,结束Sample实例及它的实例变量var1的生命周期,卸载Sample类,结束静态变量var2的生命周期,因此var4变量在Java虚拟机的运行过程中从没有被创建过。

由于局部变量和成员变量有着完全不同的生命周期,在使用局部变量时,受到以下限制:

1、局部变量不能被static、private、protected和public等修饰符修饰
因为局部变量本身就是一个访问权限的设定。只能在局部调用,也就是说局部变量的生命周期在{}之中除了这个方法外界是没办法访问你这个变量,所以不需要用任何修饰符修饰,比如private、public、protected等。但是能加final,也不能加static静态的关键词,因为static只能修饰成员变量和成员方法,在局部变量中用static修饰,又不能直接被类调用,而static关键字就是不直接过对象而用类就可以直接调用的,所以局部变量前不能加static关键字

2、不能通过类名或引用变量来访问局部变量

同理,局部变量的生命周期是在方法被调用期间存在的,作用域只在这个方法内,所以是无法被类名或引用变量来直接访问的。

扩展知识

对于局部变量,如果是基本类型,会把值直接存储在栈;如果是引用类型,比如String s = new String(“william”);会把其对象存储在堆,而把这个对象的引用(指针)存储在栈。

三、总结

静态变量的生命周期取决于类何时被加载及卸载;
实例变量的生命周期取决于实例何时被创建及销毁;
局部变量的生命周期取决于所属的方法何时被调用及结束调用。

参考链接:
https://blog.csdn.net/weixin_38756990/article/details/72857840

    原文作者:冰棍hfv
    原文地址: https://blog.csdn.net/weixin_51201930/article/details/122922364
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞