静态变量与实例变量:有何区别?

24
静态变量和实例变量有何区别?以下这句话我没理解:“在某些情况下,一个特定变量的唯一副本应该由类的所有对象共享- 这里使用静态变量。静态变量代表全局信息,类的所有对象都共享相同的数据。”
我认为实例变量是类范围内使用的,而静态变量只在其自己的方法中具有作用域?
答:静态变量是指表示整个类范围信息的变量,在某些情况下,一个特定变量应由类的所有对象共享。所有类的对象共享相同的数据。实例变量是每个类对象拥有自己副本的变量。静态变量可以在整个类中使用,而实例变量只能在特定对象的上下文中使用。

2
可能是什么是类中的'static'关键字?的重复问题。 - alex
1
你混淆了“静态的”和“局部的”。方法内声明的变量是“局部的”,只存在于该方法被调用时。 “静态”的变量类似于实例变量,但它们属于实际的“Class”对象,而不是类的特定实例,因此可以从类的所有实例中访问相同的变量。 - Hot Licks
6个回答

35

在类属性的上下文中,static 具有不同的含义。 如果您有一个字段:

private static int sharedAttribute;

然后,每个类的实例都将共享同一个变量,因此如果您在一个实例中更改它,则更改将反映在创建更改之前或之后的所有实例中。

因此,您可能会理解,在许多情况下,这是不好的,因为它很容易变成一个不希望的副作用:更改对象a也会影响b,而您可能会想知道b为什么无缘无故地发生了变化。但是,在某些情况下,这种行为绝对是可取的:

  1. 类常量:由于它们是const,让所有类都访问相同的值不会有任何伤害,因为没有人可以更改它。如果该类有很多实例,则还可以节省内存。不过并发访问尚不确定。
  2. 打算共享的变量,例如引用计数器等。

static变量在程序开始之前实例化,因此如果您有太多这样的变量,可能会减慢启动速度。

static方法只能访问static属性,但在尝试这样做之前请三思。

经验法则:除非必要且知道自己在做什么,否则不要使用static,或者您正在声明一个类常量。


2
谢谢。如果要声明静态变量,只有在我想要能够更改该类的每个对象的所有值时才会这样做,例如,如果我为员工的支付率声明了一个静态变量rate_of_pay,那么我可以通过像employee.rate_of_pay这样的操作来更新所有员工的支付率。 - user2971033
2
没错。显然,这个变化只会影响它之后发生的操作。因此,如果你想在更改费率后重新计算工资,你需要在更改后调用 recalculateWage() 或类似的函数。 - Stefano Sanfilippo

15

假设有一个测试类:

class Test{
public static int a = 5;
public int b = 10;
}
// here t1 and t2 will have a separate copy of b
// while they will have same copy of a.
Test t1 = new test(); 
Test t2 = new test();

您可以通过类名来访问静态变量,例如:

Test.a = 1//some value But you can not access instance variable like this
System.out.println(t1.a);
System.out.println(t2.a);

在这两种情况下,输出结果都将为1,因为a被测试类的所有实例共享。 而实例变量b则每个实例都有自己的副本。

 t1.b = 15 // will not be reflected in t2.
 System.out.println(t1.b); // this will print 15
 System.out.println(t2.b); / this will still print 10; 

希望这解答了您的疑问。

1
假设我们创建了一个静态变量K,在主函数中创建了三个对象:ob1、ob2和ob3。所有这些对象的变量K可以具有相同的值。相反,如果变量K是实例变量,则可以具有不同的值,如下所示: ob1.k ob2.k ob3.k

0
考虑一个类 MyClass,它有一个静态成员和一个非静态成员:
public class MyClass {
    public static int STATICVARIABLE = 0;
    public int nonStaticVariable = 0;
}

现在,让我们创建一个 main() 函数来创建一些实例:
public class AnotherClass{  
    public static void main(String[] args) {    
        // Create two instances of MyClass
        MyClass obj1  = new MyClass();
        MyClass obj2  = new MyClass();
        obj1.nonStaticVariable = 30;  // Setting value for nonstatic varibale
        obj1.STATICVARIABLE = 40; //Setting value for static variable       
        obj2.nonStaticVariable = 50;
        obj2.STATICVARIABLE = 60;

        // Print the values actually set for static and non-static variables.
        System.out.println(obj1.STATICVARIABLE);
        System.out.println(obj1.nonStaticVariable);
        System.out.println(obj2.STATICVARIABLE);
        System.out.println(obj2.nonStaticVariable);
    }
}

结果:

60
30
60
50

现在你可以看到静态变量的值60被打印了两次,因为obj1obj2都引用了同一个变量。对于非静态变量,输出不同,因为每个创建的对象都保留自己的非静态变量副本;对它们所做的更改不会影响其他对象创建的变量副本。

0

我觉得你在思考C/C++中static关键字的定义。在那里,static关键字有很多用途。在Java中,静态关键字的功能如同你所描述的。不管怎样,你可以自己试试:

public class Test_Static{
    static int x;
    public static void main(String[] argv){
        Test_Static a = new Test_Static();
        Test_Static b = new Test_Static();
        a.x = 1; // This will give an error, but still compile.
        b.x = 2;
        System.out.println(a.x); // Should print 2
    }
}

对于非静态变量同样适用:

public class Test_NonStatic{
     int x;
     public static void main(String [] argv){
         Test_NonStatic a = new Test_NonStatic();
         Test_NonStatic b = new Test_NonStatic();
         a.x = 1;
         b.x = 2;
         System.out.println(a.x); // Should print 1.
     }
}

0

实例变量

  • 在类体中定义且不在方法体外定义的任何变量;它不应该声明为静态、抽象、strictfp、synchronized 和 native 修饰符。
  • 实例变量不能脱离其对象存在,它是对象的一部分。
  • 每个对象都有自己的实例变量副本。

静态变量(类变量)

  • 使用 static 修饰符

  • 属于类(而不是类的对象)

  • 一个静态变量的副本

  • 只在执行开始时初始化一次。

  • 享受程序的生命周期


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接