为什么对象可以更改类变量的值?

时间:2015-03-14 15:10:42

标签: java

通过Oracle的definition

  

有时,您希望拥有所有对象共有的变量。这是通过静态修改器完成的。在声明中具有static修饰符的字段称为静态字段或类变量。它们与类相关联,而不是与任何对象相关联。该类的每个实例共享一个类变量,该变量位于内存中的一个固定位置。

通过这个定义,可以安全地推断静态变量属于类,并且不应该被类的任何对象访问以进行修改。因为所有对象都共享它。

因此来自同一定义的这一行有点令人困惑:

  

任何对象都可以更改类变量的值......

所以我尝试了这段代码并打印出45(虽然我收到警告说"静态成员通过实例引用&#34访问;):

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的静态变量,为什么要允许该类的一个对象更改此类变量的值?

6 个答案:

答案 0 :(得分:9)

可以 - 它只是你可以访问该变量的代码,不幸的是,Java允许你访问静态成员(包括变量和方法),就好像它们是实例成员一样。最终会产生非常误导性的代码,例如

Thread t = new Thread(...);
t.start();
t.sleep(1000);

最后一行看起来就像它要求新启动的线程休眠一样 - 但实际它会使当前线程休眠。< / p>

这基本上是Java中的一个缺陷。编译器会默默地将代码转换为

Thread.sleep(1000);

或在你的情况下

Main.value = 45;

(我相信在Java的旧版本中,它会发出使用您访问静态成员的变量检查无效的代码&#34;通过&#34;,但它甚至不会这样做更多。)

许多IDE允许您使用警告或错误标记此类代码。我鼓励你打开这样一个功能。如果您看到类似的现有代码,请将其更改为使用通过声明类直接访问静态成员,这样就可以清楚发生了什么。

答案 1 :(得分:5)

  

通过这个定义,可以安全地推断出一个静态变量属于该类,并且不应该被类的任何对象访问以进行修改。因为所有对象都共享它。

不,只要访问修饰符允许,静态字段就可以进行修改。


main.value = 45;

编译器将在编译时将此行读取为:

Main.value = 45;

答案 2 :(得分:3)

能够使用static变量和方法创建一个类,以便从类创建的所有实例或对象共享这些变量和方法非常有用,请参阅When to use static methods

在从类创建的多个实例或对象之间共享类中的static变量时,可能需要synchronized修饰符,以确保static变量正在由多个线程中的对象修改,维护数据完整性,请参阅What does synchronized mean?并查看How to synchronize a static variable among threads running different instances of a class in java

final关键字,请参阅How final keyword works用于确定变量是否是不可变的。因此,如果您想要一个应该是不可变的类static变量或常量,那么您可以将final修饰符添加到定义中。但是请参阅Java final keyword for variables,它解释了在函数式编程意味着的意义上,引用的基础值可能不是不可变的。另请参阅what is meant by immutable以及Why final keyword is necessary for immutable class

您还可以使用public等修饰符来确定类中变量和方法的可见性,请参阅What does public static void mean in Java

通过使用finalprivate等修饰符,程序员可以精确调整类中实例中变量的可见性和可修改性。

答案 3 :(得分:2)

Litle示例编译器如何将对象字段访问权限更改为类字段访问。

public class A {
    static int foo = 25;

    static public void main(String[] arg){
        B b = new B();
        A a = b;

        System.out.println(b.foo);
        System.out.println(a.foo);
    }
}

class B extends A {
    static int foo = 60;
}

输出结果为:

60
25

它还表明,由于它具有与对象字段不同的行为,因此可能会令人困惑。

答案 4 :(得分:0)

  

通过这个定义,可以安全地推断静态变量属于类,并且不应该被类的任何对象访问以进行修改。因为所有对象都共享它。

没有。根据这个定义,该静态变量属于该类, 可由该类的任何实例修改。没有任何暗示,当共享某个变量时,它不应该是可修改的。如果您愿意,请使用final

  

如果这是Student类,并且我有一个名为numberOfStudents的静态变量,为什么要允许该类的一个对象更改此类变量的值?

例如,在构造函数中递增值并在终结器中递减它。

答案 5 :(得分:0)

静态变量具有定义它的整个类的单个实例。创建实例时,该静态变量的实例不会创建。只有一个,并且可以通过任何函数自由修改,而无需实例。 (除非它被宣布为最终)