为什么对象可以改变类变量的值?
按照Oracle的定义,
有时候,你想拥有所有对象通用的变量。 这是通过静态修改器完成的。 在其声明中具有静态修饰符的字段称为静态字段或类变量。 他们与班级相关,而不是与任何对象相关联。 该类的每个实例共享一个类变量,它位于内存中的一个固定位置。
通过这个定义,推导出一个静态变量属于这个类是安全的,并且不应该被类的任何对象修改。因为所有对象都共享它。
因此,来自相同定义的这条线有点令人困惑:
任何对象都可以改变一个类变量的值...
所以我试过这段代码,它打印45(尽管我得到一个警告说“静态成员通过实例引用访问”):
public class Main {
static int value = 8;
public static void main(String[] args) {
// write your code here
Main main = new Main();
main.value = 45;
System.out.println(value);
}
}
如果这是一个Student
类,并且我有一个名为numberOfStudents
的静态变量,为什么要允许该类的一个对象更改此类变量的值?
这不是真正的“一个对象” - 它只是在代码中可以访问该变量,不幸的是,Java允许您像访问实例成员一样访问静态成员(包括变量和方法)。 这最终会导致非常令人误解的代码,例如
Thread t = new Thread(...);
t.start();
t.sleep(1000);
最后一行看起来像是要求新开始的线程休眠 - 但实际上它会使当前线程休眠。
这在Java中基本上是一个缺陷。 编译器会默默地将这样的代码转换成
Thread.sleep(1000);
或者你的情况
Main.value = 45;
(我相信在Java的一个较老的版本中,它会发出检查无效的代码,并且你正在访问静态成员的变量“through”,但它甚至没有这样做。)
许多IDE将允许您用这样的标记代码,并带有警告或错误。 我会鼓励你打开这样的功能。 如果你看到这样的代码,把它改为直接通过声明类访问静态成员,所以很清楚发生了什么。
通过这个定义,推导出一个静态变量属于这个类是安全的,并且不应该被类的任何对象修改 。因为所有对象都共享它。
不,只要访问修饰符允许,静态字段就可以进行修改。
main.value = 45;
编译器将在编译时读取这一行:
Main.value = 45;
能够创建一个具有static
变量和方法的类,以便这些变量和方法由从该类创建的所有实例或对象共享可能非常有用,请参阅何时使用静态方法。
在多个实例或从该类创建的对象之间共享类中的static
变量时,可能需要使用synchronized
修饰符,以确保如果多个线程中的对象正在修改该static
变量,则该数据完整性得到维护,看同步是什么意思? 另请参阅如何在Java中运行不同类实例的线程之间同步静态变量。
final
关键字,请参阅最终关键字如何工作用于确定变量是否是不可变的。 所以,如果你想有一个应该是不可变或者常量的类static
变量,那么你可以在定义中添加final
修饰符。 然而,请参阅Java final关键字的变量,它解释了引用的基础值在函数式编程意义上可能不是不变的。 另请参阅immutable以及为什么final关键字对于不可变类是必需的。
您还可以使用修饰符(如public
来确定类中变量和方法的可见性,请参阅Java中public static void的含义。
通过使用诸如final
或private
之类的修饰符,程序员能够精确地调整从类中实例化的类和对象中变量的可见性和可修改性。
上一篇: Why is it possible for objects to change the value of class variables?
下一篇: Difference between Synchronized block with wait/notify and without them?