Day10|Java变量全景

lazysnail2025/07/10Java基础

一、变量的本质

变量由三部分构成:

  • 类型:决定了变量能够装什么
  • 名称:变量的标识符
  • 值:变量里存储的数据本体

可以把变量理解成快递柜的格子。

类型就是格子的规格(长宽高),决定了这个格子能装多大的快递。

名称就是格子上的编号标签,让你能够快速识别到这个格子。

值自然就是放到格子里的快递包裹。

package com.lazy.snail.day10;

/**
 * @ClassName Day10Demo
 * @Description TODO
 * @Author lazysnail
 * @Date 2025/5/16 14:28
 * @Version 1.0
 */
public class Day10Demo {
    public static void main(String[] args) {
        int a = 1;

        double b = 2.0;
    }
}

示例代码中定义了两个变量:

类型分别是int\double;名称分别是a\b;值分别是1\2.0;

二、变量的分类

分类位置生命周期默认值存储位置
局部变量方法/代码块内方法执行时创建,结束销毁栈内存
实例变量类中无 static对象创建时生成堆内存
类变量(静态)类中带 static类加载时初始化,程序结束销毁方法区/元空间

局部变量

局部变量是在方法或者代码块内部声明的变量,作用域仅限其被声明的区域。

package com.lazy.snail.day10;

/**
 * @ClassName Day10Demo
 * @Description TODO
 * @Author lazysnail
 * @Date 2025/5/16 14:28
 * @Version 1.0
 */
public class Day10Demo {
    void method() {
        int a = 1;
    }
}

在方法method中声明初始化了一个a变量,这个a就只能在method中使用。

方法结束,a变量也就"消失"了。

public class Day10Demo {
    void method() {
        int a = 1;

        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
        System.out.println(a);
        System.out.println(i); // 编译错误
    }
}

for循环中使用了一个i变量,i的作用域就在for循环这个代码块中,超出这个代码块使用就会编译错误。

局部变量还有一个注意点,在使用之前必须初始化。

如果像下面这么写,一样会出现编译错误:

package com.lazy.snail.day10;

/**
 * @ClassName Day10Demo
 * @Description TODO
 * @Author lazysnail
 * @Date 2025/5/16 14:28
 * @Version 1.0
 */
public class Day10Demo {
    void method() {
        int a;
        System.out.println(a);
    }
}

IDE会提示你

img

TIP

如果你写过C/C++,你会有疑问,为什么C/C++允许没有初始化的局部变量,Java不允许。 Java只是想通过这种强制性的设置,提前暴露问题(编译期间,而不是运行时),确保安全性。

实例变量

实例变量是定义在类内部、但位于方法之外的变量,这些变量属于每个具体对象(实例)。

package com.lazy.snail.day10;

/**
 * @ClassName Student
 * @Description TODO
 * @Author lazysnail
 * @Date 2025/5/16 15:15
 * @Version 1.0
 */
public class Student {
    int id;
    String name;
}

这个Student定义了两个变量,id(学号)、name(姓名)。

我们在main方法中创建两个实例:

package com.lazy.snail.day10;

/**
 * @ClassName Student
 * @Description TODO
 * @Author lazysnail
 * @Date 2025/5/16 15:15
 * @Version 1.0
 */
public class Student {
    int id;
    String name;

    public static void main(String[] args) {
        Student student1 = new Student();
        System.out.println(student1.id);
        System.out.println(student1.name);

        Student student2 = new Student();
        System.out.println(student2.id);
        System.out.println(student2.name);
    }
}

输出发现,这两个变量好像都有默认值。int类型默认值0,String类型默认值null。

假如我们把student1的名字改成"懒惰蜗牛",student2的名字改成"蜗牛",再输出:

public static void main(String[] args) {
        Student student1 = new Student();
        student1.name = "懒惰蜗牛";
        System.out.println(student1.id);
        System.out.println(student1.name);

        Student student2 = new Student();
        student2.name = "蜗牛";
        System.out.println(student2.id);
        System.out.println(student2.name);
    }

student1和student2的name属性输出各是各的。

所以:

每个对象的实例变量独立存储,修改不影响其他对象(相当于每个对象都有变量副本)。

实例变量会自动初始化(给默认值),这点与局部变量不一样。

实例变量会随着对象的销毁而被清理。

TIP

实例变量最好使用private修饰,通过公共方法(get/set)进行访问,保证数据的安全性和可控性

类变量

类变量也可以叫静态变量或者static变量,是使用static关键字声明的变量,属于类本身,而不是具体的实例。

我们在上面Student类中加一个类变量"学校名称":

package com.lazy.snail.day10;

/**
 * @ClassName Student
 * @Description TODO
 * @Author lazysnail
 * @Date 2025/5/16 15:15
 * @Version 1.0
 */
public class Student {

    public static String schoolName = "懒惰蜗牛学院";

    int id;
    String name;

    public static void main(String[] args) {
        Student student = new Student();
        student.id = 1;
        student.name = "懒惰蜗牛";
        System.out.println(student.schoolName);
        System.out.println(Student.schoolName);
    }
}

注意最后两行输出,一个使用的是类名Student、一个使用的是实例student。

上面不是说静态变量属于类吗?为什么实例也能访问?

那是因为编译器悄悄的把实例访问转换成了类名访问。

public static void main(String[] args) {
        Student student = null;
        System.out.println(student.schoolName);
}

student明明是null,用他去访问任何东西不是应该抛出NullPointerException吗?

运行一下,看看输出,正常输出了"懒惰蜗牛学院"。

其实这跟上面是一个道理,静态变量的访问,编译器都做了转换。

所以:

所有实例共享同一个类变量,内存中仅存一份。

类在被加载的时候,静态变量就会初始化(自动初始化默认值),程序结束,才销毁。

直接通过类名进行访问(不需要创建对象)。

TIP

虽然可以通过实例名访问静态变量,但是不推荐。

不可变变量

final修饰的变量表示****不可变的值或引用。

这个修饰符可以用来修饰上面我们提到的局部变量、成员、静态变量。

修饰局部变量

声明的时候直接初始化

void method() {
    final int a = 2;
}

延迟初始化

void method() {
    final int a;
    a = 2;
}

如果你在a初始化后(已经赋值为2),想要修改a的值:

void method() {
    final int a;
    a = 2;
    a = 3;
}

会得到一个编译错误:

img

修饰实例变量

必须在声明的时候或构造方法/实例初始化块****中赋值。

package com.lazy.snail.day10;

/**
 * @ClassName Day10Demo
 * @Description TODO
 * @Author lazysnail
 * @Date 2025/5/16 14:28
 * @Version 1.0
 */
public class Day10Demo {
    final int a = 5;
    final int b;

    public Day10Demo() {
        b = 10;
    }
}

a是在声明时就初始化的;b是在构造方法中才初始化的。

修饰类变量

必须在声明的时候或者静态初始化块里赋值。

package com.lazy.snail.day10;

/**
 * @ClassName Day10Demo
 * @Description TODO
 * @Author lazysnail
 * @Date 2025/5/16 14:28
 * @Version 1.0
 */
public class Day10Demo {
    static final int A = 1;
    static final int B;
    static {
        B = 2;
    }
}

A是在声明时初始化的;B是在静态代码块时初始化的。(这里名称大写是规范,不是强制性要求)

TIP

一般常量的标准写法是全大写 + 下划线分隔

所以:

final修饰的变量只能赋值一次,一旦初始化了,值或者引用就不能修改了。

必须初始化,要在声明的时候或者构造方法或者静态代码块中显式的赋值。

三、变量新特性

var局部变量类型推断

var是Java10引入的,编译器可以根据初始化值自动推断局部变量的类型。

package com.lazy.snail.day10;

/**
 * @ClassName Day10Demo
 * @Description TODO
 * @Author lazysnail
 * @Date 2025/5/16 14:28
 * @Version 1.0
 */
public class Day10Demo {
    public static void main(String[] args) {
        int a = 1;
        var b = 1;
    }
}

b变量会被自动推断为int类型。

这个类型推断只适用于局部变量。

必须显示的初始化(不然没有推断依据了)。

不能用于方法参数、返回值或成员变量。

TIP

不要滥用var,否则未来哪一天的你看不懂你现在写的代码。

四、变量设计的一些原则

作用域最小化:限制变量的可见范围,降低耦合,不要动不动就全局变量。

不可变性优先:多用final,减少状态变化带来的复杂性。

命名即注释:就是所谓的见名知意,通过名称传达变量用途,减少注释依赖。

类型选择策略:基本类型追求性能,引用类型面向抽象。

结语

变量是Java程序的核心数据载体,分为基本类型(直接存储值)与引用类型(存储对象地址),作用域涵盖局部变量(栈内存)、实例变量(堆内存)和类变量(方法区)。

通过final关键字实现不可变性,保障数据安全;

遵循驼峰命名和类型精准化原则,提升代码可读性。

变量管理体现程序的状态逻辑和封装性,是构建健壮、可维护系统的基础。

最后更新 7/10/2025, 11:14:05 AM