静态变量与实例变量
一. 静态变量与实例变量
静态变量: 通过 static 修饰的成员变量,称静态变量,也叫类变量;
实例变量:独立于方法之外,没有 static 修饰的成员变量,叫做实例变量;
public class User { // 静态变量 (类变量) public static String userDepartment ; // 实例变量 private String name; // 实例变量 private Integer age; }
静态变量:
1. 静态变量在类里定义,声明变量时,在变量类型前面加上 static 即可,但必须在方法之外;
2. 静态变量没有被显式地初始化时,会被赋予默认值。数值型变量默认值是 0(或者0.0),布尔型默认值是 false,引用类型默认值是 null;
3. 静态变量可以直接在该类的方法里使用,通过访问 类名.静态属性名,如:User.userDepartment ,不需要创建实例,就可以直接通过类调用;
4. 静态变量所属于类,被类中所有对象共享,任意一个对象修改了被static修饰的内容,其他所有对象访问到的数据都是修改之后的;
5. 静态变量先按顺序分配内存,分配完后,再按顺序赋值;
6. 静态变量储存在方法区(Method Area),与类的字节码一起被加载到内存中;
7. 静态变量的生命周期,随着类加载,随着类消失;
8. 静态变量被final修饰,final代表最终,不可改变,静态常量,变量名称一般建议使用大写字母,若多个单词组成,使用下划线连接单词 如:public static final String user_department;
9. 静态变量被final修饰,对于基本类型和String类型,直接使用显示赋值(直接赋值常量,而非调用方法); && 如果final修饰的是引用Class类呢?? 答案是无法为最终可变用户部门分配值,需要去掉final修饰。
实例变量:
1. 实例变量声明在一个类中,但在方法、构造方法和语句块之外 ;
2. 实例变量没有被显式地初始化时,会被赋予默认值。数值型变量的默认值是0(或者0.0),布尔型变量的默认值是false,引用类型变量的默认值是null;
3. 实例变量是必须要实例化对象后才可以调用,通过实例对象名.属性名,如:先实例:User user = new User(); 在调用:user.getName();
4. 实例变量的生命周期与其所属的对象相同。当对象被创建时,实例变量分配内存空间;当对象不再被引用时,垃圾回收器会回收实例变量所占用的内存空间;
5. 实例变量建议使用访问修饰符修饰,实例变量的可见性取决于其访问修饰符;
6. 实例变量在程序执行过程中会存储在堆内存中。每创建一个对象,都会为其分配一块内存空间来存储实例变量;
7. 实例变量可以在声明时进行初始化,也可以在构造方法中进行初始化。在构造方法中初始化的实例变量可以根据不同对象的需求设置不同的值。
二. 实例变量和静态变量的区别
1. 定义不用:实例变量属于类的实例(对象),每个对象都有独立的实例变量副本。而静态变量属于类本身,在整个类的实例中共享。
2. 存储位置:实例变量存储在堆内存中,每个对象都有自己的一份实例变量。而静态变量存储在方法区或静态存储区中,所有对象共享同一份静态变量。
3. 内存大小:实例变量根据实例对象的份数决定占用内存空间,而静态变量在类加载过程,JVM只会分配一次内存空间。
3. 生命周期:实例变量的生命周期与对象的生命周期相同,当对象被销毁时,实例变量也会被回收。而静态变量的生命周期长于对象,直到程序退出或静态变量被显式地销毁。
4. 访问方式:实例变量只能通过对象来访问,需要先创建对象才能使用实例变量。而静态变量可以通过类名直接访问,不需要创建对象。
5. 数据共享:实例变量适合存储对象的特有状态,每个对象都有独立的实例变量,不会相互影响。而静态变量适合存储与类相关的全局信息,所有对象共享同一份静态变量,可以实现数据的共享和交互。
三. 扩展
1. 静态变量的加载顺序:
① 静态变量分配内存空间:在程序运行时,静态变量的内存空间会被分配。
② 默认初始化:如果静态变量没有显示赋初值,那么系统会给它们赋予默认初值。对于基本数据类型,通常是0或者null;对于引用类型,默认为null。
③ 显式初始化:如果静态变量有显示的赋初值语句,在类加载过程中会被执行。
④ 静态代码块:如果静态变量的初始化包含在静态代码块中,那么静态代码块会在显式初始化之前执行。
⑤ 静态变量的加载和赋值完成后,才能访问和使用它们。
小案例:
public class Test { static int i = getNum(); int j = getNum(); static int num = 1; static int getNum() { return num; } public static void main(String[] args) { Test t1 = new Test(); System.out.println("i="+i); System.out.println("j="+t1.j); } }
执行结果: i = 0 , j = 1 ;
执行顺序:
1. <clinit>类初始化:static变量分配内存空间 ;
static int i ; 先声明,分配内存空间,未赋值,默认值0 ;
static int num ; 先声明,分配内存空间,未赋值,默认值 0;
2. <clinit>类初始化:static int i = getNum(); 执行静态方法:static int getNum() { return num;} 此处num没有赋值,仍是默认值0;
3. <clinit>类初始化:static变量赋值:
static int i = 0 ; 静态方法getNum()中仍是默认值,从类中取到的是0,所以赋值为0;
static int num = 1; 此时num被赋值为1;
4. <clinit>类初始化:类初始化结束。static int getNum() { return num;} 静态方法随着类加载已执行过了。
5. <init>对象初始化:执行 Test t1 = new Test();
调用new 操作符,根据实例变量的类型和定义时所指定的初始值(如有)分配堆内存的空间
调用Class 或 java.lang.reflect.Constructor 对象的newInstance()方法
初始化实例对象 赋值
6. <init>对象初始化: 实例变量 int j = getNum(); 调用静态方法static int getNum() { return num;}
int j = 1; 此处 num=1,return 后 赋值给 j ;
7. main方法执行: 完成 Test t1 = new Test(); 将new 出来的实例引用到 t1;
打印输出: i=0 j=1 ;
(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤ 完!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)