== with Enum name() and toString() [duplicate] - java

This question already has answers here:
Are enum names interned in Java?
(4 answers)
Closed 1 year ago.
Can anyone explain why toString() and name() are referencing the same String? when I used == to compare them with a String literal they all pass! How does enum name work with String pool from JVM?
static enum User
{
BASIC, PREMIUM;
}
System.out.println("BASIC" == User.BASIC.toString()); // true
System.out.println("BASIC" == User.BASIC.name()); // true

Well, Enum.name() and Enum.toString() return the same private field, so the references are always going to be the same. Both calls return name and name == name is always going to be true.
To better answer your question, however, the JVM's internal string pool stores only one copy of distinct strings. You're only requesting one distinct string, "BASIC", and since Strings are immutable it is stored only once so .toString() and .name() would likely return the same reference even if those calls were returning different fields.
EDIT:
Also, string literals (strings in quotes in source code) are all gathered up at compile time and any duplicates are all mapped to the same reference. So if, for instance, you have places all over your source code where you're using the literal "Hello I am a string literal", then that exact string is only stored one time and, since strings are immutable and will never change, every place that used that literal in your source code now uses a reference to the single place where it's stored in the JVM String pool. This is because, if possible, it's obviously better to not make a bunch of copies of the same thing. That's a vast oversimplification but you get the idea.

Compiling your enum class and disassembling with javap -verbose gives this (partial) output:
final class User extends java.lang.Enum<User>
minor version: 0
major version: 52
flags: ACC_FINAL, ACC_SUPER, ACC_ENUM
Constant pool:
#7 = String #13 // BASIC
#9 = Fieldref #4.#38 // User.BASIC:LUser;
#10 = String #15 // PREMIUM
#11 = Fieldref #4.#39 // User.PREMIUM:LUser;
#13 = Utf8 BASIC
#15 = Utf8 PREMIUM
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=4, locals=0, args_size=0
0: new #4 // class User
3: dup
4: ldc #7 // String BASIC
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field BASIC:LUser;
13: new #4 // class User
16: dup
17: ldc #10 // String PREMIUM
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field PREMIUM:LUser;
26: iconst_2
27: anewarray #4 // class User
30: dup
31: iconst_0
32: getstatic #9 // Field BASIC:LUser;
35: aastore
36: dup
37: iconst_1
38: getstatic #11 // Field PREMIUM:LUser;
41: aastore
42: putstatic #1 // Field $VALUES:[LUser;
45: return
LineNumberTable:
line 1: 0
By the time that an enum is compiled, it's just an ordinary Java .class file, whose only distinguishing features at runtime are the fact that it extends Enum and has the ACC_ENUM flag set; everything else is just plain bytecode.
To set up the enum constants, including their names, the compiler could theoretically use complicated reflection to derive the names from the value names, but instead it's far simpler and just as effective to inline the names as string constants. The static initializer loops through the names, calling the private constructor to instantiate the value instances and assign them to the private $VALUES array.
As these strings are in the constant pool, the usual deduplication logic then applies. toString() returns the same object because its default implementation is simply to return name.

because the enum class in java looks like this:
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
private final String name;
public final String name() {
return name;
}
private final int ordinal;
public final int ordinal() {
return ordinal;
}
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
public String toString() {
return name;
}
in general you should compare enums with == but if you want to use the name pls use .equals()

The JVM implementation is reusing the same String constant, because they're both loaded in the same class at the same time. That is an optimization made by the specific JVM implementation you're using (and probably most of the existing ones). If you did this, you would get false.
String s = (new StringBuilder("BAS")).append("IC").toString();
System.out.println(s == User.BASIC.toString());
This is because the String reference s is created at runtime.
You would also likely get false if they're loaded from different classes.

Related

Calling Instance Method with 'this' vs. calling it without 'this' - is there a difference?

Is there any difference between the call to getName() on line 8 and that on line 9.
If yes, then what is it?
This might be very simple but I did my Google search and the only SO result I got was about using this with a field, and not with a method.
class CallingInstanceMethodWithAndWithoutThis {
private String getName() {
return "Zarah";
}
private void printGetName() {
System.out.println(getName());
System.out.println(this.getName());
}
public static void main(String [] args) {
new CallingInstanceMethodWithAndWithoutThis().printGetName();
}
}
There is no difference, it is just a coding convention to use. Moreover you can ask Eclipse for instance to remove automatically "this" when not needed as a Save Action.
There is no difference between using this and not using it.
To check this, in fact, if we perform disassemble using javap -p -c CallingInstanceMethodWithAndWithoutThis the output is below :
private void printGetName();
Code:
0: getstatic #19 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: invokespecial #25 // Method getName:()Ljava/lang/String;
7: invokevirtual #27 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: getstatic #19 // Field java/lang/System.out:Ljava/io/PrintStream;
13: aload_0
14: invokespecial #25 // Method getName:()Ljava/lang/String;
17: invokevirtual #27 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
We can notice that the output at line 0 and line 10 (where we are calling getName() method) are same and there is no difference.
For the compiler there is no difference, but it may cause collisions in some cases. Generally not using this will be OK, java compiler is smart enough to recognize our intentions, but it is strongly recommended to use this keyword anyway (e.g. in setters), IMO it's more clear to understand where the method comes from (in case your class extends other or you import some methods statically).

Why initialize a final static variable in static block? e.g. public static final Object o; static { o = new ...} [duplicate]

This question already has answers here:
What is the difference between a static and a non-static initialization code block
(9 answers)
Closed 7 years ago.
Someone explain to me the differences between the following two statements?
A static final variable initialized by a static code block:
private static final String foo;
static { foo = "foo"; }
A static final variable initialized by an assignment:
private static final String foo = "foo";
In this example, there's one subtle difference - in your first example, foo isn't determined to be a compile-time constant, so it can't be used as a case in switch blocks (and wouldn't be inlined into other code); in your second example it, is. So for example:
switch (args[0]) {
case foo:
System.out.println("Yes");
break;
}
That's valid when foo is deemed to be a constant expression, but not when it's "just" a static final variable.
However, static initializer blocks are usually used when you have more complicated initialization code - such as populating a collection.
The timing for initialization is described in JLS 12.4.2; any static final fields which are considered as compile-time constants are initialized first (step 6) and initializers are run later (step 9); all initializers (whether they're field initializers or static initializers) are run in textual order.
private static final String foo;
static { foo ="foo";}
The value of foo is initialized when the class is loaded and static initializers are run.
private static final String foo = "foo";
Here, the value of foo will be a compile-time constant. So, in reality "foo" will be available as part of th byte-code itself.
In IInd case- value of foo is early bind ie compiler identifies and assign value foo to variable FOO, which cant be changed,and this will be available apart with byte-code itself.
private static final String FOO = "foo";
and In Ist case-value of foo initialize just after class loading as a very first assignment before instance variable assigned,also here you can catch exceptions or static field can be assign by calling static methods in static block.
private static final String FOO;
static { FOO ="foo";}
So whenever there is a condition arrive when compiler must have to identify the value of variable foo, condition II will work,for ex-like value of case: in switch cases.
The JLS describes a few special behaviors of what it calls constant variables, which are final variables (whether static or not) which are initialized with constant expressions of String or primitive type.
Constant variables have a major difference with respect to binary compatibility: the values of constant variables become part of the class's API, as far as the compiler is concerned.
An example:
class X {
public static final String XFOO = "xfoo";
}
class Y {
public static final String YFOO;
static { YFOO = "yfoo"; }
}
class Z {
public static void main(String[] args) {
System.out.println(X.XFOO);
System.out.println(Y.YFOO);
}
}
Here, XFOO is a "constant variable" and YFOO is not, but they are otherwise equivalent. Class Z prints out each of them. Compile those classes, then disassemble them with javap -v X Y Z, and here is the output:
Class X:
Constant pool:
#1 = Methodref #3.#11 // java/lang/Object."<init>":()V
#2 = Class #12 // X
#3 = Class #13 // java/lang/Object
#4 = Utf8 XFOO
#5 = Utf8 Ljava/lang/String;
#6 = Utf8 ConstantValue
#7 = String #14 // xfoo
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = NameAndType #8:#9 // "<init>":()V
#12 = Utf8 X
#13 = Utf8 java/lang/Object
#14 = Utf8 xfoo
{
public static final java.lang.String XFOO;
descriptor: Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: String xfoo
X();
descriptor: ()V
flags:
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
}
Class Y:
Constant pool:
#1 = Methodref #5.#12 // java/lang/Object."<init>":()V
#2 = String #13 // yfoo
#3 = Fieldref #4.#14 // Y.YFOO:Ljava/lang/String;
#4 = Class #15 // Y
#5 = Class #16 // java/lang/Object
#6 = Utf8 YFOO
#7 = Utf8 Ljava/lang/String;
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 <clinit>
#12 = NameAndType #8:#9 // "<init>":()V
#13 = Utf8 yfoo
#14 = NameAndType #6:#7 // YFOO:Ljava/lang/String;
#15 = Utf8 Y
#16 = Utf8 java/lang/Object
{
public static final java.lang.String YFOO;
descriptor: Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
Y();
descriptor: ()V
flags:
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #2 // String yfoo
2: putstatic #3 // Field YFOO:Ljava/lang/String;
5: return
}
Class Z:
Constant pool:
#1 = Methodref #8.#14 // java/lang/Object."<init>":()V
#2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Class #17 // X
#4 = String #18 // xfoo
#5 = Methodref #19.#20 // java/io/PrintStream.println:(Ljava/lang/String;)V
#6 = Fieldref #21.#22 // Y.YFOO:Ljava/lang/String;
#7 = Class #23 // Z
#8 = Class #24 // java/lang/Object
#9 = Utf8 <init>
#10 = Utf8 ()V
#11 = Utf8 Code
#12 = Utf8 main
#13 = Utf8 ([Ljava/lang/String;)V
#14 = NameAndType #9:#10 // "<init>":()V
#15 = Class #25 // java/lang/System
#16 = NameAndType #26:#27 // out:Ljava/io/PrintStream;
#17 = Utf8 X
#18 = Utf8 xfoo
#19 = Class #28 // java/io/PrintStream
#20 = NameAndType #29:#30 // println:(Ljava/lang/String;)V
#21 = Class #31 // Y
#22 = NameAndType #32:#33 // YFOO:Ljava/lang/String;
#23 = Utf8 Z
#24 = Utf8 java/lang/Object
#25 = Utf8 java/lang/System
#26 = Utf8 out
#27 = Utf8 Ljava/io/PrintStream;
#28 = Utf8 java/io/PrintStream
#29 = Utf8 println
#30 = Utf8 (Ljava/lang/String;)V
#31 = Utf8 Y
#32 = Utf8 YFOO
#33 = Utf8 Ljava/lang/String;
{
Z();
descriptor: ()V
flags:
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String xfoo
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: getstatic #6 // Field Y.YFOO:Ljava/lang/String;
14: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
17: return
}
Things to notice in the disassembly, which tell you the differences between X and Y run deeper than syntactic sugar:
XFOO has a ConstantValue attribute, signifying that its value is a compile-time constant. Whereas YFOO does not, and uses a static block with a putstatic instruction to initialize the value at runtime.
The String constant "xfoo" has become part of class Z's constant pool, but "yfoo" has not.
Z.main uses the ldc (load constant) instruction to load "xfoo" onto the stack directly from its own constant pool, but it uses a getstatic instruction to load the value of Y.YFOO.
Other differences you will find:
If you change the value of XFOO and recompile X.java but not Z.java, you have a problem: class Z is still using the old value. If you change the value of YFOO and recompile Y.java, class Z uses the new value whether you recompile Z.java or not.
If you delete the X.class file entirely, class Z still runs correctly. Z has no runtime dependency on X. Whereas if you delete the Y.class file, class Z fails to initialize with a ClassNotFoundException: Y.
If you generate documentation for the classes with javadoc, the "Constant Field Values" page will document the value of XFOO, but not the value of YFOO.
The JLS describes the above effects constant variables have on compiled class files in §13.1.3:
A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.
If such a field is static, then no reference to the field should be present in the code in a binary file, including the class or interface which declared the field. Such a field must always appear to have been initialized (§12.4.2); the default initial value for the field (if different than V) must never be observed.
If such a field is non-static, then no reference to the field should be present in the code in a binary file, except in the class containing the field. (It will be a class rather than an interface, since an interface has only static fields.) The class should have code to set the field's value to V during instance creation (§12.5).
And in §13.4.9:
If a field is a constant variable (§4.12.4), and moreover is static, then deleting the keyword final or changing its value will not break compatibility with pre-existing binaries by causing them not to run, but they will not see any new value for a usage of the field unless they are recompiled.
[...]
The best way to avoid problems with "inconstant constants" in widely-distributed code is to use static constant variables only for values which truly are unlikely ever to change. Other than for true mathematical constants, we recommend that source code make very sparing use of static constant variables.
The upshot is that if your public library exposes any constant variables, you must never change their values if your new library version is otherwise supposed to be compatible with code compiled against old versions of the library. It won't necessarily cause an error, but the existing code will probably malfunction since it will have outdated ideas about the values of constants. (If your new library version needs for classes which use it to be recompiled anyway, then changing constants doesn't cause this problem.)
Thus, initializing a constant with a block gives you more freedom to change its value, because it prevents the compiler embedding the value into other classes.
The only difference is the initialization time.
Java first initializes the members and then the static blocks.
An additional aspect: Consider the case when you have multiple static fields, and yes this is a corner case...
As stated in Jon Skeet's answer, the JLS defines the exact order of initialization.
However, if for some reason you have to initialize multiple static attributes in a specific order, you may want to make the initialization sequence clearly visible in the code.
When using direct field initialization: Some code formatters (and developers) may decide at some point to sort fields differently, this will directly impact how the fields get initialized and introduce unwanted effects.
By the way, if you want to follow common java coding conventions, you should use capital letters when defining 'constants' (final static fields).
--- edited reflecting Jon Skeet's comments ---
Static block give you more than simple statement. In this particular case is the same thing.
Static section will be executed at class load time, before any instances constructed. You can call methods here and assign their results to static fields. And you can catch exceptions in static blocks.

Java final field compile-time constant expression

The below text is from jls http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3
Even then, there are a number of complications. If a final field is
initialized to a compile-time constant expression (§15.28) in the
field declaration, changes to the final field may not be observed,
since uses of that final field are replaced at compile time with the
value of the constant expression.
Can anyone please give me better explanation for the above. I couldn't understand the statement "changes to the final field may not be observed". May with the help of example.
I couldn't understand the statement changes to the final field may not be observed
It tells that , if a final variable is declared as compile time constant then any change made in the final variable using reflection API further in program will not be visible to the program during execution.
For example consider the code given below:
import java.lang.reflect.*;
class ChangeFinal
{
private final int x = 20;//compile time constant
public static void change(ChangeFinal cf)
{
try
{
Class clazz = ChangeFinal.class;
Field field = clazz.getDeclaredField("x");
field.setAccessible(true);
field.set(cf , 190);//changed x to 190 for object cf
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
public static void main(String[] args)
{
ChangeFinal cf = new ChangeFinal();
System.out.println(cf.x);//prints 20
change(cf);
System.out.println(cf.x);//prints 20
}
}
The Output of the above code is:
20
20
WHY?
The answer lies in the output provided by javap -c command for public static void main:
public static void main(java.lang.String[]);
Code:
0: new #3; //class ChangeFinal
3: dup
4: invokespecial #11; //Method "<init>":()V
7: astore_1
8: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream;
11: aload_1
12: invokevirtual #13; //Method java/lang/Object.getClass:()Ljava/lang/Cla
ss;
15: pop
16: bipush 20
18: invokevirtual #14; //Method java/io/PrintStream.println:(I)V
21: aload_1
22: invokestatic #15; //Method change:(LChangeFinal;)V
25: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream;
28: aload_1
29: invokevirtual #13; //Method java/lang/Object.getClass:()Ljava/lang/Cla
ss;
32: pop
33: bipush 20
35: invokevirtual #14; //Method java/io/PrintStream.println:(I)V
38: return
}
At line 16 (before changeFinal method is called)the value of cf.x is hardcoded to 20 . And at line 33 (after changeFinal method is called) the value of cf.x is again hardcoded to 20. Therefore , Although the change in the value of final variable x is done successfully by reflection API during execution, but because of x being a compile time constant it is showing its constant value 20.
It means if in a class you have this:
public class Foo {
public final boolean fooBoolean = true; // true is a constant expression
public final int fooInt = 5; // 5 is a constant expression
}
At compile time any reference to Foo.fooBoolean may be replaced with true, and references to Foo.fooInt may be replaced by 5. If at runtime you later change either of those final fields via reflection, the code referencing it (as it was written) may never see it.
It is quite possible for a Java program to observe a final field having two different values at different times, even without reflection, without recompiling multiple versions of the class, and without anything along those lines. Consider the class below:
class X {
static final int x = getX();
static int getX() {
System.out.println("X.x is now " + X.x);
return 1;
}
public static void main(String[] args) {
System.out.println("X.x is now " + X.x);
}
}
Output:
X.x is now 0
X.x is now 1
This happens because some of the code (the first println) is executed before the field's value is assigned, so that code observes the field's default initial value of 0. The field has a default initial value before it is assigned, even though it is final, because it is not a constant field. The text you quoted from the JLS says this kind of thing cannot happen if the field is declared as a constant.

String Constant Pool vs String pool

I am confused about these two things. I need a help. Please clear my doubt, whether String Constant Pool and String pool both are same concept. I faced this question on interview. I have already read lot of sites and blogs but, my doubt is not cleared.Please clear my doubts.
Thanks in Advance.
Both are the same thing. String Constant Pool contains constant string objects. Constant can be defined as String object holds the value at compile time. For more refer JLS.
String s="abc";
String s1="def";
String s2=s+"def";
String s3="abc"+"def";
System.out.println(s2==s3); // print false
But if you make s as final then
final String s="abc";
String s1="def";
String s2=s+"def";
String s3="abc"+"def";
System.out.println(s2==s3); // print true
In above case s3 is a compile time constant as s is final .
The String pool (= "String constant pool"):
This is an informal nickname given to String's class-level/static intern storage. Note: javadoc mentions "pool of strings" http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#intern%28%29.
It's a set containing every unique String value interned during app execution. Interning happens automatically for all compile-time String constants (literals and fixed expressions) and also for all runtime String values where String.intern() is called. The JLS mandates that compile-time constant expressions of type String are always "interned" so as to share unique instances, using the method String.intern. http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28
The JVM spec does not mandate any particular internal structure for objects. http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.7
The Java Language Spec does mandate that a String object has a constant (unchanging) value. http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.3.3
That means that a String variable can only change value by referencing a new String object with a new value - of course, this is internally managed by the compiler & JVM . That also means that all items in the pool are String constants.
The Constant Pool (not focused on Strings, but does include Strings):
Exists within each class file (and in memory, for each class loaded). Is a per-class record of the constants (i.e. final variables) in use. http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4 http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.5.5
I thought about it and I'm not sure but the string pool may refer to the string literal pool, stuff like String apple = "apple"; where as the String constant pool may refer to the constant string objects like those using the keyword final, although to receive a question with tricky semantics like that would annoy me if I got it in an interview
String Pool (String Constant/Memory/Literals Pool) vs Constant Pool
When compiler meets any string literal, compiler puts it into String Constant Pool. All the method or class variables refer to that string constant pool;
class MemoryModel { final String s = "abc"; String s5 = "abc";}
:
String s1 = "abc";
MemoryModel mm = new MemoryModel();
System.out.println("abc".hashCode()); //12345
System.out.println(mm.s.hashCode()); //12345
System.out.println(mm.s5.hashCode()); //12345
System.out.println(s1.hashCode()); //12345
String "abc" will go to String pool, whereas s,s5 will go in constant pool (or Runtime Constant Pool) of class MemoryModel. ‘s1’ is method local variable so it’ll be saved in JVM frame.
A string literal always refers to the same instance of class String.
Literal strings in any class of any package represent references to
the same String object.
Strings computed by constant expressions are computed at compile time and then treated as if they were literals.
Example 2
public method(){
final String s="abc";
String s1="def";
final String s2=s+s1;
String s3=s+"def";
String s4="abc"+"def";
}
For above method nothing will be saved in Class Constant Pool. “abc”, “def”, and “abcdef” will be saved in String pool.
"abcdef".hashCode() == ("abc" + "def").hashCode() //true
Bytecode for above method;
0: ldc #19 // String abc
2: astore_1
3: ldc #21 // String def
5: astore_2
6: new #23 // class java/lang/StringBuilder
9: dup
10: ldc #19 // String abc
12: invokespecial #25 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
15: astore_3
16: aload_3
17: aload_2
18: invokevirtual #28 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: invokevirtual #32 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
24: astore 4
26: ldc #36 // String abcdef
28: astore 5
30: ldc #36 // String abcdef
32: astore 6
34: return
Above bytecode suggests that nothing is put into CP (Constant Pool). For above code s3 == s4 and s3 == “abcdef” because all final constants are replaced with their value at the time of compilation. So the above code will be converted to this;
final String s="abc";
String s1="def";
final String s2=new StringBuilder("abc").append(s1).toString();
String s3="abc"+"def";
String s4="abc"+"def";
But if ‘s’ is not final then
String s="abc";
String s1="def";
final String s2=new StringBuilder(s).append(s1).toString();
String s3=new StringBuilder(s).append("def").toString();
String s4="abc"+"def";
In above code, s2 and s3 will be pointing a new instance of String having char[]. So s3 and s4 are not same.
Example 3
public class MemoryModel {
final String s="abc";
String s1="def";
final String s2=s+s1;
String s3=s+"def";
String s4="abc"+"def";
String s5=s2;
}
Bytecode for this is pretty much similar to above bytecode. But you’ll see few more entries of putfield and getfield which tells us that constant are put into CP.
Let’s compare byte code for above code;
With Final 's'
21: ldc #8 // String abc
23: invokespecial #27 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
26: aload_0
27: getfield #23 // Field s1:Ljava/lang/String;
30: invokevirtual #30 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
33: invokevirtual #34 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
36: putfield #38 // Field s2:Ljava/lang/String;
Without Final 's'
21: aload_0
22: getfield #18 // Field s:Ljava/lang/String;
25: invokestatic #26 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
28: invokespecial #32 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
31: aload_0
32: getfield #22 // Field s1:Ljava/lang/String;
35: invokevirtual #35 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
38: invokevirtual #39 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
41: putfield #43 // Field s2:Ljava/lang/String;
And
With Final 's'
39: aload_0
40: ldc #40 // String abcdef
42: putfield #42 // Field s3:Ljava/lang/String;
Without Final 's'
44: aload_0
45: new #24 // class java/lang/StringBuilder
48: dup
49: aload_0
50: getfield #18 // Field s:Ljava/lang/String;
53: invokestatic #26 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
56: invokespecial #32 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
59: ldc #20 // String def
61: invokevirtual #35 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
64: invokevirtual #39 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
67: putfield #45 // Field s3:Ljava/lang/String;
This comparison also proves that the value of final variable is replaced at the time of comparison. And the constant fields are saved into CP. So if ‘s’ is not final then the value of ‘s is taken from CP using getfield.

Nested get performance

In Java, is there a performance hit if i continually use nested get to retrieve values? For instance:
String firstname = getOffice().getDepartment().getEmployee().getFirstName();
String lastname = getOffice().getDepartment().getEmployee().getLastName();
String address = getOffice().getDepartment().getEmployee().getAddress();
VS:
Employee e = getOffice().getDepartment().getEmployee();
String firstname = e.getFirstName();
String lastname = e.getLastName();
String address = e.getAddress();
Would the 2nd version be faster because it has less 'jumps'?
It depends entirely on what the getXYZ calls do. If they're simple accessors to an underlying field, then no, not on HotSpot (Oracle's JVM), because they'll get optimized out if there's any need to do so. If, on the other hand, they do any kind of complex work (traversing a btree, etc.), then of course they'll have to do that work repeatedly (unless HotSpot can prove to itself that the calls are idempotent, which if the code has any complexity becomes unlikely). (Whether it matters that they do the work repeatedly is another question; until/unless you see an actual performance problem, don't worry about it.)
But the second is much more readable and maintainable. That's the more powerful reason for using it.
Rather than performance I see second as better human understandable code. You should not worry about micro optimizations but write a good and clean code.
The optimization you are thinking about is called premature optimization. You should not think about these unless you really have to.
I agree with #AmitD's answer about being the second one more readable. When chaining method calls like this, you can also write them in the following way -
Employee e = getOffice()
.getDepartment()
.getEmployee();
String firstname = e.getFirstName();
String lastname = e.getLastName();
String address = e.getAddress();
to further improve readability.
Possibly yes. But assuming the getters look like ordinary getters on the inside it will probably be so small that it becomes almost impossible to measure.
Also if you run through this code often enough to make it matter, the magic of the Hotspot compiler will kick in and mangle the byte code, probably again making both variations the same.
In the end it is extremely hard to tell what really will happen. If performance matters for you set up a test. If performance doesn't matter enough to justify the costs of the test ... well then it doesn't matter enough to worry.
Either use byte code analysis or time the two approaches using System.nanoTime. I think second one is faster. here is what I did to conclude this:
I wrote three classes as given below:
public static class A {
public B b = new B();
}
public static class B {
public E e = new E();
}
public static class E {
public String name = "s";
public int age = 1;
}
Then I wrote two simple methods and get their java byte code using javap -c CLASS_NAME.
public static void Test1() {
A a = new A();
String str = a.b.e.name;
int age = a.b.e.age;
}
The byte code of above method is:
public static void Test1();
Code:
// new A();
0: new #15
3: dup
4: invokespecial #17
7: astore_0
8: aload_0
// a.b (it accesses the field and put it on operand stack)
9: getfield #18
// b.e
12: getfield #22
// b.name
15: getfield #28
// pop 'name' from stack
18: astore_1
19: aload_0
// cyle continues
20: getfield #18
23: getfield #22
26: getfield #34
29: istore_2
30: return
You can clearly see at byte code level, each time you try to access field, it put the value of that filed on stack and then this cycle continues. Therefore, a.a1.a2....an would be n instruction if stack would have enough spae to hold all n. And there was no optimisation by compiler this same cycle of called again to access both name and age field.
Now here is the second method:
public static void Test2() {
A a = new A();
E e = a.b.e;
String str = e.name;
int age = e.age;
}
Byte code for above method is:
public static void Test2();
Code:
// new A();
0: new #15
3: dup
4: invokespecial #17
7: astore_0
8: aload_0
// store a.b.e on operand stack once
9: getfield #18
12: getfield #22
15: astore_1
16: aload_1
// get 'name' field
17: getfield #28
20: astore_2
21: aload_1
// get 'age' field
22: getfield #34
25: istore_3
26: return
Above is 4 instruction shorter than previous code as it prevents execution of getfield. So I think this should be faster than previous one.

Categories