views:

135

answers:

6

When I define constant values in my Java code, I generally declare them 'private static final', but recently I've been maintaining code where the constants are defined 'private final'.

I'm optimizing at the moment and was wondering whether to 'static'ize these.

For example

public class X {
    private final String SOME_CONST = "Whatever";
}

Is the above code equivalent (at run-time) to the following, so only 1 copy of 'SOME_CONST' is held?

public class X {
    private static final String SOME_CONST = "Whatever";
}

I would have thought this was fairly basic, but I can't find the answer anywhere.

[Edit] Some people have answered on the String instance being interned. Sorry, I should have picked a better example, in the case I'm looking at, it's not just Strings, but a lot of different types (some standard, some user defined).

I'm more interested in the effects of the 'private final' versus a 'private static final' declaration.

+4  A: 

When SOME_CONST is declared non-static, the virtual machine will create one String instance whose content is "Whatever". However, all instances of the X class will contain a reference to this String object. Therefore, there is only one instance of your String, but many references to it.

It would probably be worthwhile to make that field static so as to avoid the unnecessary references.

Adam Paynter
+2  A: 

Nope. In both cases, there is only one String instance of "Whatever", as all String literals are interned.

When the field is static, then there is only one reference to the String instance, from the X.class object. However, in the case of non-static field, then each object would contain a different reference to the String instance.

In other words, making the field non-static would cause a constance reference overhead (~ 32-bits or 64-bit) for each object.

notnoop
But what if we had this instead?private final String SOME_CONST = new String("Whatever");In this case the String is not interned and each class will point to a different String.
pjp
@pjp, when using an initializer, then there will be multiple instances when non-static field. In the case of static field, only one instance will be initialized.
notnoop
A: 

final strings are used inline when compiled. So if you write

final String a="A";
void foo(){ System.out.println(a):}

the compiler writes

final String a="A";
void foo(){ System.out.println("A"):}

However as far as I can see the compiler does not write this as a static - you'll still have the reference declared in each instance.

Steve B.
+1  A: 

There is one caveat to making a final a static final, that is if there is a method building the variable. If there is more than one instance of the variable with a dynamic set, then the value of the variable gets stuck. Many times finals are created dynamically for performance reasons; this is dangerous, as someone may decide to optimize the code and static them.

In your example there is no issue, but if you are going to have more than one instance of the Class or Method where the variable is set and it is set dynamically, make sure that there is no static modifier to the final. Unless there is a large loop where the var is being set, the danger of breaking code is not worth the very small performance gain.

WolfmanDragon
Nope, the point of the question was that the members are set to constant values on declaration, not set dynamically
GKelly
A: 

FindBugs helpfully points out that such a final member should be static. One could infer from that that the optimization doesn't take place.

banjollity
That's what I thought. Thanks
GKelly
A: 

If you have

public class X {
    private final SomeClass FIELD = new SomeClass();
}

the compiler has no way to optimize this and has to create new instance of SomeClass each time you create a new instance of X. How is it to know the SomeClass constructor doesn't read something from some stream or open some DB connection? In this case optimizing to static would break the code.

EDIT

Change from

final SomeClass FIELD = new SomeClass();

to

static final SomeClass FIELD = new SomeClass();

is a change from situation when each instance of X has its own instance of SomeClass to situation when all instances of X share the same instance of SomeClass. It may change nothing except for efficiency or it may break all the code (imagine one JDBC connection shared by every instance versus one connection per class instance). It depends of the SomeClass implementation and of the use that is made of it.

Tadeusz Kopec