私有最终静态属性vs私有最终属性

时间:2009-09-12 19:49:35

标签: java static attributes private final

在Java中,有什么区别:

private final static int NUMBER = 10;

private final int NUMBER = 10;

两者都是privatefinal,区别在于static属性。

什么更好?为什么?

22 个答案:

答案 0 :(得分:289)

通常,static表示“与类型本身相关联,而不是与该类型的实例相关联。”

这意味着您可以引用静态变量而无需创建该类型的实例,并且引用该变量的任何代码都指的是完全相同的数据。将其与实例变量进行比较:在这种情况下,每个类的实例都有一个独立的变量版本。例如:

Test x = new Test();
Test y = new Test();
x.instanceVariable = 10;
y.instanceVariable = 20;
System.out.println(x.instanceVariable);

打印出10:y.instanceVariablex.instanceVariable是分开的,因为xy指的是不同的对象。

可以通过引用来引用静态成员,尽管这样做是个坏主意。如果我们这样做:

Test x = new Test();
Test y = new Test();
x.staticVariable = 10;
y.staticVariable = 20;
System.out.println(x.staticVariable);

然后打印出20 - 只有一个变量,而不是每个实例一个变量。把它写成:

会更清楚
Test x = new Test();
Test y = new Test();
Test.staticVariable = 10;
Test.staticVariable = 20;
System.out.println(Test.staticVariable);

这使得行为更加明显。现代IDE通常会建议将第二个列表更改为第三个列表。

没有理由拥有诸如

之类的声明
private final int NUMBER = 10;

如果无法更改,则每个实例都没有一个副本。

答案 1 :(得分:37)

对于 final ,初始化时可以在运行时为其分配不同的值。 例如

Class Test{
  public final int a;
}

Test t1  = new Test();
t1.a = 10;
Test t2  = new Test();
t2.a = 20; //fixed

因此,每个实例都具有不同的字段值 a

对于静态最终,所有实例共享相同的值,并且在首次初始化后不能更改。

Class TestStatic{
      public static final int a;
}

TestStatic t1  = new TestStatic();
t1.a = 10;
TestStatic t2  = new TestStatic();
t1.a = 20;   // ERROR, CAN'T BE ALTERED AFTER THE FIRST INITIALIZATION.

答案 2 :(得分:25)

static变量在应用程序的整个生命周期内保留在内存中,并在类加载期间初始化。每次构造static对象时,都会初始化非new变量。通常最好使用:

private static final int NUMBER = 10;

为什么呢?这减少了每个实例的内存占用量。它可能也有利于缓存命中。它才有意义:static应该用于某种类型的所有实例(a.k.a.对象)共享的东西(a.k.a。class)。

答案 3 :(得分:16)

静态意味着“与班级相关”;没有它,变量与类的每个实例相关联。如果它是静态的,那意味着你只有一个在内存中;如果没有,您将为您创建的每个实例分配一个。 static表示只要加载类,变量就会保留在内存中;如果没有它,变量的实例可以是gc'd。

答案 4 :(得分:12)

阅读答案我发现没有真正的测试真正达到目的。这是我的2美分:

public class ConstTest
{

    private final int         value             = 10;
    private static final int  valueStatic       = 20;
    private final File        valueObject       = new File("");
    private static final File valueObjectStatic = new File("");

    public void printAddresses() {


        System.out.println("final int address " +
                ObjectUtils.identityToString(value));
        System.out.println("final static int address " +
                ObjectUtils.identityToString(valueStatic));
        System.out.println("final file address " + 
                ObjectUtils.identityToString(valueObject));
        System.out.println("final static file address " + 
                ObjectUtils.identityToString(valueObjectStatic));
    }


    public static void main(final String args[]) {


        final ConstTest firstObj = new ConstTest();
        final ConstTest sndObj = new ConstTest();

        firstObj.printAdresses();
        sndObj.printAdresses();
    }

}

第一个对象的结果:

final int address java.lang.Integer@6d9efb05
final static int address java.lang.Integer@60723d7c
final file address java.io.File@6c22c95b
final static file address java.io.File@5fd1acd3

第二个对象的结果:

final int address java.lang.Integer@6d9efb05
final static int address java.lang.Integer@60723d7c
final file address java.io.File@3ea981ca
final static file address java.io.File@5fd1acd3

结论:

我认为java会对原语和其他类型产生影响。 Java中的原始类型总是“缓存”,对于字符串文字(不是新的String对象)也是如此,因此静态和非静态成员之间没有区别。

但是,如果非静态成员不是基本类型的实例,则存在重复内存。

将valueStatic的值更改为10甚至会更进一步,因为Java将为两个int变量提供相同的地址。

答案 5 :(得分:9)

虽然其他答案似乎很清楚,通常没有理由使用非静态常量,但我找不到任何人指出可能在其常量变量上有不同值的各种实例。

考虑以下示例:

public class TestClass {
    private final static double NUMBER = Math.random();

    public TestClass () {
        System.out.println(NUMBER);
    }
}

创建三个TestClass实例将打印相同的随机值三次,因为只生成一个值并将其存储到静态常量中。

但是,在尝试以下示例时:

public class TestClass {
    private final double NUMBER = Math.random();

    public TestClass () {
        System.out.println(NUMBER);
    }
}

创建三个TestClass实例现在将打印三个不同的随机值,因为每个实例都有自己随机生成的常量值。

我无法想到在不同的实例上使用不同的常量值非常有用的任何情况,但我希望这有助于指出静态和非静态终结之间存在明显差异。

答案 6 :(得分:2)

正如Jon所说,静态变量(也称为类变量)是一个跨类实例存在的变量。

我找到了这个here的一个例子:

public class StaticVariable
{
  static int noOfInstances;
  StaticVariable()
  {
    noOfInstances++;
  }
  public static void main(String[] args)
  {
    StaticVariable sv1 = new StaticVariable();
    System.out.println("No. of instances for sv1 : " + sv1.noOfInstances);

    StaticVariable sv2 = new StaticVariable();
    System.out.println("No. of instances for sv1 : "  + sv1.noOfInstances);
    System.out.println("No. of instances for st2 : "  + sv2.noOfInstances);

    StaticVariable sv3 = new StaticVariable();
    System.out.println("No. of instances for sv1 : "  + sv1.noOfInstances);
    System.out.println("No. of instances for sv2 : "  + sv2.noOfInstances);
    System.out.println("No. of instances for sv3 : "  + sv3.noOfInstances);
  }
}

该计划的输出如下:

正如我们在本例中所见,每个对象都有自己的类变量副本。

C:\java>java StaticVariable
No. of instances for sv1 : 1
No. of instances for sv1 : 2
No. of instances for st2 : 2
No. of instances for sv1 : 3
No. of instances for sv2 : 3
No. of instances for sv3 : 3

答案 7 :(得分:2)

这是我的两分钱:

final           String CENT_1 = new Random().nextInt(2) == 0 ? "HEADS" : "TAILS";
final   static  String CENT_2 = new Random().nextInt(2) == 0 ? "HEADS" : "TAILS";

示例:

package test;

public class Test {

    final long OBJECT_ID = new Random().nextLong();
    final static long CLASSS_ID = new Random().nextLong();

    public static void main(String[] args) {
        Test[] test = new Test[5];
        for (int i = 0; i < test.length; i++){
            test[i] = new Test();
            System.out.println("Class id: "+test[i].CLASSS_ID);//<- Always the same value
            System.out.println("Object id: "+test[i].OBJECT_ID);//<- Always different
        }
    }
}

关键是变量和函数可以返回不同的值。因此可以为最终变量赋值不同。

答案 8 :(得分:2)

从我所做的测试中,静态最终变量与最终(非静态)变量不同!最终(非静态)变量可能因对象而异!但这只是在构造函数中进行初始化的时候! (如果它没有从构造函数初始化,那么它只是浪费内存,因为它为每个创建的无法更改的对象创建最终变量。)

例如:

class A
{
    final int f;
    static final int sf = 5;

    A(int num)
    {
        this.f = num;
    }

    void show()
    {
        System.out.printf("About Object: %s\n Final: %d\n Static Final: %d\n\n", this.toString(), this.f, sf);
    }

    public static void main(String[] args)
    {
        A ob1 = new A(14);
        ob1.show();

        A ob2 = new A(21);
        ob2.show();

    }
}

屏幕上显示的是:

关于对象:@ addbf1  决赛:14  静态决赛:5

关于对象:@ 530daa  决赛:21  静态决赛:5

匿名的第一年IT学生,希腊

答案 9 :(得分:2)

此外,对于Jon的回答,如果你使用静态final,它将表现为一种“定义”。一旦你编译了使用它的类,它就会被编译的.class文件烧掉。 检查我的帖子here

为了您的主要目标:如果您在课程的不同实例中不使用NUMBER,我建议使用final和static。 (你必须记住不要复制已编译的类文件而不考虑我的案例研究所描述的可能的麻烦。大多数情况都不会发生,不要担心:))

为了向您展示如何在实例中使用不同的值,请检查以下代码:

public class JustFinalAttr {
  public final int Number;

  public JustFinalAttr(int a){
    Number=a;
  }
}

...System.out.println(new JustFinalAttr(4).Number);

答案 10 :(得分:1)

由于类中的变量在同一命令中被声明为final AND initialised, 绝对没有理由不将它声明为静态,因为无论实例如何它都具有相同的值。因此,所有实例都可以为一个值共享相同的内存地址,从而无需为每个实例创建一个新变量,并通过共享一个公共地址来节省内存,从而节省了处理时间。

答案 11 :(得分:1)

private static final将被视为常量,并且只能在此类中访问常量。因为,包含关键字static,所以该类的所有对象的值都是常量。

私有最终变量值将类似于每个对象的常量。

您可以参考java.lang.String或查找下面的示例。

fileprivate init(startNode: Element?) {
    currentNode = startNode
}

//输出:

public final class Foo
{

    private final int i;
    private static final int j=20;

    public Foo(int val){
        this.i=val;
    }

    public static void main(String[] args) {
        Foo foo1= new Foo(10);

        Foo foo2= new Foo(40);

        System.out.println(foo1.i);
        System.out.println(foo2.i);
        System.out.println(check.j);
    }
}

答案 12 :(得分:1)

很少,而且是静态的

没有太大区别,因为它们都是常数。对于大多数类数据对象,static意味着与类本身相关联的东西,无论使用new创建了多少个对象,都只有一个副本。

由于它是一个常量,它实际上可能不会存储在类或实例中,但编译器仍然不允许您从静态方法访问实例对象,即使它知道它们会是什么是。如果不使它成为静态的,反射API的存在也可能需要一些毫无意义的工作。

答案 13 :(得分:0)

让我们说如果该类不会有多个实例,那么哪一个需要更多内存:

private static final int ID = 250; 要么 private final int ID = 250;

我已经了解静态将引用类型,内存中只有一个副本,非静态将位于每个实例变量的新内存位置。但是在内部,如果我们只是比较同一个类的1个实例(即不会创建多于1个实例),那么1个静态最终变量使用的空间是否有任何开销?

答案 14 :(得分:0)

静态变量属于该类(这意味着所有对象共享该变量)。非静态变量属于每个对象。

public class ExperimentFinal {

private final int a;
private static final int b = 999; 

public ExperimentFinal(int a) {
    super();
    this.a = a;
}
public int getA() {
    return a;
}
public int getB() {
    return b;
}
public void print(int a, int b) {
    System.out.println("final int: " + a + " \nstatic final int: " + b);
}
public static void main(String[] args) {
    ExperimentFinal test = new ExperimentFinal(9);
    test.print(test.getA(), test.getB());
} }

正如你可以看到上面的例子,对于“final int”我们可以为类的每个实例(对象)分配我们的变量,但是对于“static final int”,我们应该在类中分配一个变量(静态变量所属)到了班级。)

答案 15 :(得分:0)

如果您将此变量标记为静态然后如您所知,您将需要静态方法再次访问这些值,如果您已经考虑过只在静态方法中使用这些变量,这将非常有用。如果是这样,那么这将是最好的。

然而,您可以将变量现在设为公开,因为没有人可以像“System.out”那样修改它,它又取决于您的意图和您想要实现的目标。

答案 16 :(得分:0)

静态的一个是所有类实例和类本身的相同成员 非静态是每个实例(对象)的一个,所以在您的确切情况中,如果放置静态,则会浪费内存。

答案 17 :(得分:0)

另一个简单的例子来理解静态,静态final,final变量的用法。代码注释有正确的解释。

public class City {

    // base price that is always same for all objects[For all cities].
    private static double iphone_base_price = 10000;

    // this is total price = iphone_base_price+iphone_diff;
    private double iphone_citi_price;

    // extra price added to iphone_base_price. It is constant per city. Every
    // city has its own difference defined,
    private final double iphone_diff;

    private String cityName = "";

    // static final will be accessible everywhere within the class but cant be
    // changed once initialized.
    private static final String countryName = "India";

    public City(String cityName, double iphone_diff) {
        super();
        this.iphone_diff = iphone_diff;
        iphone_citi_price = iphone_base_price + iphone_diff;
        this.cityName = cityName;

    }

    /**
     * get phone price
     * 
     * @return
     */
    private double getPrice() {

        return iphone_citi_price;
    }

    /**
     * Get city name
     * 
     * @return
     */
    private String getCityName() {

        return cityName;
    }

    public static void main(String[] args) {

        // 300 is the
        City newyork = new City("Newyork", 300);
        System.out.println(newyork.getPrice() + "  " + newyork.getCityName());

        City california = new City("California", 800);
        System.out.println(california.getPrice() + "  " + california.getCityName());

        // We cant write below statement as a final variable can not be
        // reassigned
        // california.iphone_diff=1000; //************************

        // base price is defined for a class and not per instances.
        // For any number of object creation, static variable's value would be the same
        // for all instances until and unless changed.
        // Also it is accessible anywhere inside a class.
        iphone_base_price = 9000;

        City delhi = new City("delhi", 400);
        System.out.println(delhi.getPrice() + "  " + delhi.getCityName());

        City moscow = new City("delhi", 500);
        System.out.println(moscow.getPrice() + "  " + moscow.getCityName());

        // Here countryName is accessible as it is static but we can not change it as it is final as well. 
        //Something are meant to be accessible with no permission to modify it. 
        //Try un-commenting below statements
        System.out.println(countryName);

        // countryName="INDIA";
        // System.out.println(countryName);

    }

}

答案 18 :(得分:0)

如果使用static,变量的值在所有实例中都是相同的,如果在一个实例中更改,其他实例也会更改。

答案 19 :(得分:0)

最终值:分配了最终变量后,它始终包含相同的值。 无论变量是否为静态 静态:对于在内存中一次初始化的所有实例,它只是一个变量

答案 20 :(得分:0)

“ Static”关键字使类成为变量属性,而不是该类的各个实例。该变量的一个副本将在该类的所有实例之间共享。静态变量状态的任何更改都将反映在所有实例中。将final添加到static中,我们得到一个变量,该变量在类加载时已被彻底初始化,以后该类的任何实例都无法更改。静态最终变量需要在声明时进行初始化,否则会出现编译时错误。 就私有实例字段而言,它指的是对象的属性/状态/类的实例。该类的每个实例/对象将具有其自己的实例变量副本。当实例变量声明为final时,这意味着我们无法为此实例更改其值。为此,我们需要在声明或构造函数中初始化最终变量,如果在两个变量中均未完成,则会显示编译时错误。初始化后,如果您尝试重新分配值,则会收到编译时错误。使用静态最终变量,其中数据将在类的所有实例之间共享,并且您希望数据是只读的。如果您要表示属于类的每个单独实例的某些数据,请使用实例最终变量。存储无法更改。静态关键字和实例关键字的使用取决于您的设计需求以及该数据在域中表示的内容。如果在类实例之间使用数据,则无需为每个对象单独复制/存储引用。

答案 21 :(得分:-1)

这可能会有所帮助

public class LengthDemo {
public static void main(String[] args) {
    Rectangle box = new Rectangle();
    System.out.println("Sending the value 10.0 "
            + "to the setLength method.");
    box.setLength(10.0);
    System.out.println("Done.");
    }
}