I had learned that in Java the static block gets executed when the class is initialized and instance block get executed before the construction of each instance of the class . I had always seen the static block to execute before the instance block . Why the case is opposite for enums ?
Can anyone please explain me the output of the sample code :
enum CoffeeSize {
BIG(8), LARGE(10),HUGE(12),OVERWHELMING();
private int ounces ;
static {
System.out.println("static block ");
}
{
System.out.println("instance block");
}
private CoffeeSize(int ounces){
this.ounces = ounces;
System.out.println(ounces);
}
private CoffeeSize(){
this.ounces = 20;
System.out.println(ounces);
}
public int getOunces() {
return ounces;
}
}
Output:
instance block
8
instance block
10
instance block
12
instance block
20
static block
You need to know that enum values are static fields which hold instances of that enum type, and initialization order of static fields depends on their position.
See this example
class SomeClass{
public SomeClass() { System.out.println("creating SomeClass object"); }
}
class StaticTest{
static{ System.out.println("static block 1"); }
static SomeClass sc = new SomeClass();
static{ System.out.println("static block 2"); }
public static void main(String[] args) {
new StaticTest();
}
}
output
static block 1
creating SomeClass object
static block 2
Now since enum values are always placed at start of enum type, they will always be called before any static initialization block, because everything else can only be declared after enum values.
BUT initialization of enum values (which happens at class initialization) their constructors are called and as you said non-static initialization blocks are executed at start of every constructor which is why you see them:
for every enum value
and before any static initialization block.
Little late and building up on Pshemo's answer. The output of the (compiling) code below is as follows:
8
10
Foo
static block
Bar
So the enum constant initializations are executed first (as Pshemo said, they are always implicitly static and final, see second blockquote) and then all fields explicitly declared as static are initialized. As mentioned, the language specification says this about the order of execution during class initialization and about enum constants:
Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.
In addition to the members that an enum type E inherits from Enum, for each declared enum constant with the name n, the enum type has an implicitly declared public static final field named n of type E. These fields are considered to be declared in the same order as the corresponding enum constants, before any static fields explicitly declared in the enum type.
class StaticTest {
enum CoffeeSize {
BIG(8), LARGE(10);
private int ounces;
static Foo foo = new Foo();
static { System.out.println("static block "); }
static Bar bar = new Bar();
private CoffeeSize(int ounces){
this.ounces = ounces;
System.out.println(ounces);
}
}
public static void main(String[] args) {
CoffeeSize cs = CoffeeSize.LARGE;
}
}
class Foo { public Foo() { System.out.println("Foo"); } }
class Bar { public Bar() { System.out.println("Bar"); } }
Use bytecode to make out this problem.
import java.util.ArrayList;
import java.util.List;
public enum EnumDemo {
ONE(1), TWO(2);
private final static List<Integer> vals;
static {
System.out.println("fetch instance from static");
vals = new ArrayList<>();
EnumDemo[] values = EnumDemo.values();
for (EnumDemo value : values) {
vals.add(value.val);
}
}
private int val;
EnumDemo(int val){
this.val = val;
System.out.println("create instance:" + val);
}
}
use javac compile to class file, and then javap -c EnumDemo.class, got this:
Compiled from "EnumDemo.java"
public final class EnumDemo extends java.lang.Enum<EnumDemo> {
public static final EnumDemo ONE;
public static final EnumDemo TWO;
public static EnumDemo[] values();
Code:
0: getstatic #1 // Field $VALUES:[LEnumDemo;
3: invokevirtual #2 // Method "[LEnumDemo;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LEnumDemo;"
9: areturn
public static EnumDemo valueOf(java.lang.String);
Code:
0: ldc_w #4 // class EnumDemo
3: aload_0
4: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
7: checkcast #4 // class EnumDemo
10: areturn
static {};
Code:
0: new #4 // class EnumDemo
3: dup
4: ldc #16 // String ONE
6: iconst_0
7: iconst_1
8: invokespecial #17 // Method "<init>":(Ljava/lang/String;II)V
11: putstatic #18 // Field ONE:LEnumDemo;
14: new #4 // class EnumDemo
17: dup
18: ldc #19 // String TWO
20: iconst_1
21: iconst_2
22: invokespecial #17 // Method "<init>":(Ljava/lang/String;II)V
25: putstatic #20 // Field TWO:LEnumDemo;
28: iconst_2
29: anewarray #4 // class EnumDemo
32: dup
33: iconst_0
34: getstatic #18 // Field ONE:LEnumDemo;
37: aastore
38: dup
39: iconst_1
40: getstatic #20 // Field TWO:LEnumDemo;
43: aastore
44: putstatic #1 // Field $VALUES:[LEnumDemo;
47: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
50: ldc #21 // String fetch instance from static
52: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
55: new #22 // class java/util/ArrayList
58: dup
59: invokespecial #23 // Method java/util/ArrayList."<init>":()V
62: putstatic #24 // Field vals:Ljava/util/List;
65: invokestatic #25 // Method values:()[LEnumDemo;
68: astore_0
69: aload_0
70: astore_1
71: aload_1
72: arraylength
73: istore_2
74: iconst_0
75: istore_3
76: iload_3
77: iload_2
78: if_icmpge 109
81: aload_1
82: iload_3
83: aaload
84: astore 4
86: getstatic #24 // Field vals:Ljava/util/List;
89: aload 4
91: getfield #7 // Field val:I
94: invokestatic #26 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
97: invokeinterface #27, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
102: pop
103: iinc 3, 1
106: goto 76
109: return
}
So, enum instance is the static instance, and at the head.
1. An enum type is a type whose fields consist of a fixed set of constants. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.
2. They are static final constant, therefore have all letters in Caps.
3. And static variables are initialized as soon as the JVM loads the class.
For further details see this link:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/enums.html
Related
I was teaching students the old-school Generics and came across an unseen! behavior while I was presenting! :(
I have a simple class
public class ObjectUtility {
public static void main(String[] args) {
System.out.println(castToType(10,new HashMap<Integer,Integer>()));
}
private static <V,T> T castToType(V value, T type){
return (T) value;
}
}
This gives output as 10,without any error!!! I was expecting this to give me a ClassCastException, with some error like Integer cannot be cast to HashMap.
Curious and Furious, I tried getClass() on the return value, something like below
System.out.println(castToType(10,new HashMap<Integer,Integer>()).getClass());
which is throwing a ClassCastException as I expected.
Also, when I break the same statement into two, something like
Object o = castToType(10,new HashMap<Integer,Integer>());
System.out.println(o.getClass());
It is not throwing any error and prints class java.lang.Integer
All are executed with
openjdk version "1.7.0_181"
OpenJDK Runtime Environment (Zulu 7.23.0.1-macosx) (build 1.7.0_181-b01)
OpenJDK 64-Bit Server VM (Zulu 7.23.0.1-macosx) (build 24.181-b01, mixed mode)
Can someone point me in the right direction on Why this behaviour is happening?
T doesn't exist at runtime. It resolves to the lower bound of the constraint. In this case, there are none, so it resolves to Object. Everything can be cast to Object, so no class cast exception.
If you were to do change the constraint to this
private static <V,T extends Map<?,?>> T castToType(V value, T type){
return (T) value;
}
then the cast to T becomes a cast to the lower bound Map, which obviously Integer is not, and you get the class cast exception you're expecting.
Also, when I break the same statement into two, something like
Object o = castToType(10,new HashMap<Integer,Integer>());
System.out.println(o.getClass());
It is not throwing any error
castToType(10,new HashMap<Integer,Integer>()).getClass()
This throws a class cast exception because it statically links to the method HashMap::getClass (not Object::getClass) since the signature says to expect HashMap as a return value. This necessitates an implicit cast to HashMap which fails because castToType returns an Integer at runtime.
When you use this first
Object o = castToType(10,new HashMap<Integer,Integer>());
you are now statically linking against Object::getClass which is fine regardless of what's actually returned.
The "unsplit" version is equivalent to this
final HashMap<Integer, Integer> map = castToType(10, new HashMap<>());
System.out.println(map.getClass());
which hopefully demonstrates the difference
You could see the differences using javap tool.
The compiling process by default makes code optimizations that changes the Generic types into the primitive ones
First code:
public class ObjectUtility {
public static void main(String[] args) {
System.out.println(castToType(10,new java.util.HashMap<Integer,Integer>()));
}
private static <V,T> T castToType(V value, T type){
return (T) value;
}
}
Real PseudoCode:
Compiled from "ObjectUtility.java"
public class ObjectUtility {
public ObjectUtility();
descriptor: ()V
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: bipush 10
5: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
8: new #4 // class java/util/HashMap
11: dup
12: invokespecial #5 // Method java/util/HashMap."<init>":()V
15: invokestatic #6 // Method castToType:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
18: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
21: return
LineNumberTable:
line 4: 0
line 5: 21
private static <V, T> T castToType(V, T);
descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
Code:
0: aload_0
1: areturn
LineNumberTable:
line 8: 0
}
The calls of the Generic types are changed to Object and an Integer.valueOf is added on the System out print.
Second code:
public class ObjectUtility {
public static void main(String[] args) {
System.out.println(castToType(10,new java.util.HashMap<Integer,Integer>()).getClass());
}
private static <V,T> T castToType(V value, T type){
return (T) value;
}
}
Real Pseudo Code:
Compiled from "ObjectUtility.java"
public class ObjectUtility {
public ObjectUtility();
descriptor: ()V
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: bipush 10
5: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
8: new #4 // class java/util/HashMap
11: dup
12: invokespecial #5 // Method java/util/HashMap."<init>":()V
15: invokestatic #6 // Method castToType:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
18: checkcast #4 // class java/util/HashMap
21: invokevirtual #7 // Method java/lang/Object.getClass:()Ljava/lang/Class;
24: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
27: return
LineNumberTable:
line 4: 0
line 5: 27
private static <V, T> T castToType(V, T);
descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
Code:
0: aload_0
1: areturn
LineNumberTable:
line 8: 0
}
The checkcast is invoqued over HashMap but the signature is changed to Object and the returnt is the value as int without the cast inside castToType. The "int" primitive type causes an invalid cast
Third Code:
public class ObjectUtility {
public static void main(String[] args) {
Object o = castToType(10,new java.util.HashMap<Integer,Integer>());
System.out.println(o.getClass());
}
private static <V,T> T castToType(V value, T type){
return (T) value;
}
}
Real Pseudo Code:
Compiled from "ObjectUtility.java"
public class ObjectUtility {
public ObjectUtility();
descriptor: ()V
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
Code:
0: bipush 10
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: new #3 // class java/util/HashMap
8: dup
9: invokespecial #4 // Method java/util/HashMap."<init>":()V
12: invokestatic #5 // Method castToType:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
15: astore_1
16: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #7 // Method java/lang/Object.getClass:()Ljava/lang/Class;
23: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
26: return
LineNumberTable:
line 4: 0
line 5: 16
line 6: 26
private static <V, T> T castToType(V, T);
descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
Code:
0: aload_0
1: areturn
LineNumberTable:
line 9: 0
}
At this case the method is similar to the first one. castToType returns the first parameter without change.
As you can see the java compiler mades some "performance" changes that could affect in some cases. The Generics are an "invention" of the source code that are finally converted to the real type required in any case.
I need to convert an ordinal int value to an enum value in Java. Which is simple:
MyEnumType value = MyEnumType.values()[ordinal];
The values() method is implicit, and I cannot locate the source code for it, hence the question.
Does the MyEnumType.values() allocate a new array or not? And if it does, should I cache the array when first called? Suppose that the conversion will be called quite often.
Yes.
Java doesn't have mechanism which lets us create unmodifiable array. So if values() would return same mutable array, we risk that someone could change its content for everyone.
So until unmodifiable arrays will be introduced to Java, for safety values() must return new/separate array holding all values.
We can test it with == operator:
MyEnumType[] arr1 = MyEnumType.values();
MyEnumType[] arr2 = MyEnumType.values();
System.out.println(arr1 == arr2); //false
If you want to avoid recreating this array you can simply store it and reuse result of values() later. There are few ways to do it, like.
you can create private array and allow access to its content only via getter method like
private static final MyEnumType[] VALUES = values();// to avoid recreating array
MyEnumType getByOrdinal(int){
return VALUES[int];
}
you can store result of values() in unmodifiable collection like List to ensure that its content will not be changed (now such list can be public).
public static final List<MyEnumType> VALUES = Collections.unmodifiableList(Arrays.asList(values()));
Theoretically, the values() method must return a new array every time, since Java doesn't have immutable arrays. If it always returned the same array it could not prevent callers muddling each other up by modifying the array.
I cannot locate the source code for it
The values() method has no ordinary source code, being compiler-generated. For javac, the code that generates the values() method is in com.sun.tools.javac.comp.Lower.visitEnumDef. For ECJ (Eclipse's compiler), the code is in org.eclipse.jdt.internal.compiler.codegen.CodeStream.generateSyntheticBodyForEnumValues.
An easier way to find the implementation of the values() method is by disassembling a compiled enum. First create some silly enum:
enum MyEnumType {
A, B, C;
public static void main(String[] args) {
System.out.println(values()[0]);
}
}
Then compile it, and disassemble it using the javap tool included in the JDK:
javac MyEnumType.java && javap -c -p MyEnumType
Visible in the output are all the compiler-generated implicit members of the enum, including (1) a static final field for each enum constant, (2) a hidden $VALUES array containing all the constants, (3) a static initializer block that instantiates each constant and assigns each one to its named field and to the array, and (4) the values() method that works by calling .clone() on the $VALUES array and returning the result:
final class MyEnumType extends java.lang.Enum<MyEnumType> {
public static final MyEnumType A;
public static final MyEnumType B;
public static final MyEnumType C;
private static final MyEnumType[] $VALUES;
public static MyEnumType[] values();
Code:
0: getstatic #1 // Field $VALUES:[LMyEnumType;
3: invokevirtual #2 // Method "[LMyEnumType;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LMyEnumType;"
9: areturn
public static MyEnumType valueOf(java.lang.String);
Code:
0: ldc #4 // class MyEnumType
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class MyEnumType
9: areturn
private MyEnumType(java.lang.String, int);
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #6 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
6: return
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: invokestatic #8 // Method values:()[LMyEnumType;
6: iconst_0
7: aaload
8: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
11: return
static {};
Code:
0: new #4 // class MyEnumType
3: dup
4: ldc #10 // String A
6: iconst_0
7: invokespecial #11 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #12 // Field A:LMyEnumType;
13: new #4 // class MyEnumType
16: dup
17: ldc #13 // String B
19: iconst_1
20: invokespecial #11 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #14 // Field B:LMyEnumType;
26: new #4 // class MyEnumType
29: dup
30: ldc #15 // String C
32: iconst_2
33: invokespecial #11 // Method "<init>":(Ljava/lang/String;I)V
36: putstatic #16 // Field C:LMyEnumType;
39: iconst_3
40: anewarray #4 // class MyEnumType
43: dup
44: iconst_0
45: getstatic #12 // Field A:LMyEnumType;
48: aastore
49: dup
50: iconst_1
51: getstatic #14 // Field B:LMyEnumType;
54: aastore
55: dup
56: iconst_2
57: getstatic #16 // Field C:LMyEnumType;
60: aastore
61: putstatic #1 // Field $VALUES:[LMyEnumType;
64: return
}
However, the fact that the values() method has to return a new array, doesn't mean the compiler has to use the method. Potentially a compiler could detect use of MyEnumType.values()[ordinal] and, seeing that the array is not modified, it could bypass the method and use the underlying $VALUES array. The above disassembly of the main method shows that javac does not make such an optimization.
I also tested ECJ. The disassembly shows ECJ also initializes a hidden array to store the constants (although the Java langspec doesn't require that), but interestingly its values() method prefers to create a blank array then fill it with System.arraycopy, rather than calling .clone(). Either way, values() returns a new array every time. Like javac, it doesn't attempt to optimize the ordinal lookup:
final class MyEnumType extends java.lang.Enum<MyEnumType> {
public static final MyEnumType A;
public static final MyEnumType B;
public static final MyEnumType C;
private static final MyEnumType[] ENUM$VALUES;
static {};
Code:
0: new #1 // class MyEnumType
3: dup
4: ldc #14 // String A
6: iconst_0
7: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #19 // Field A:LMyEnumType;
13: new #1 // class MyEnumType
16: dup
17: ldc #21 // String B
19: iconst_1
20: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #22 // Field B:LMyEnumType;
26: new #1 // class MyEnumType
29: dup
30: ldc #24 // String C
32: iconst_2
33: invokespecial #15 // Method "<init>":(Ljava/lang/String;I)V
36: putstatic #25 // Field C:LMyEnumType;
39: iconst_3
40: anewarray #1 // class MyEnumType
43: dup
44: iconst_0
45: getstatic #19 // Field A:LMyEnumType;
48: aastore
49: dup
50: iconst_1
51: getstatic #22 // Field B:LMyEnumType;
54: aastore
55: dup
56: iconst_2
57: getstatic #25 // Field C:LMyEnumType;
60: aastore
61: putstatic #27 // Field ENUM$VALUES:[LMyEnumType;
64: return
private MyEnumType(java.lang.String, int);
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #31 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
6: return
public static void main(java.lang.String[]);
Code:
0: getstatic #35 // Field java/lang/System.out:Ljava/io/PrintStream;
3: invokestatic #41 // Method values:()[LMyEnumType;
6: iconst_0
7: aaload
8: invokevirtual #45 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
11: return
public static MyEnumType[] values();
Code:
0: getstatic #27 // Field ENUM$VALUES:[LMyEnumType;
3: dup
4: astore_0
5: iconst_0
6: aload_0
7: arraylength
8: dup
9: istore_1
10: anewarray #1 // class MyEnumType
13: dup
14: astore_2
15: iconst_0
16: iload_1
17: invokestatic #53 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
20: aload_2
21: areturn
public static MyEnumType valueOf(java.lang.String);
Code:
0: ldc #1 // class MyEnumType
2: aload_0
3: invokestatic #59 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #1 // class MyEnumType
9: areturn
}
However, it's still potentially possible that the JVM could have an optimization that detects the fact that the array is copied and then thrown away, and avoids it. To test that, I ran the following pair of benchmark programs that test ordinal lookup in a loop, one which calls values() each time and the other that uses a private copy of the array. The result of the ordinal lookup is assigned to a volatile field to prevent it being optimized away:
enum MyEnumType1 {
A, B, C;
public static void main(String[] args) {
long t = System.nanoTime();
for (int n = 0; n < 100_000_000; n++) {
for (int i = 0; i < 3; i++) {
dummy = values()[i];
}
}
System.out.printf("Done in %.2f seconds.\n", (System.nanoTime() - t) / 1e9);
}
public static volatile Object dummy;
}
enum MyEnumType2 {
A, B, C;
public static void main(String[] args) {
long t = System.nanoTime();
for (int n = 0; n < 100_000_000; n++) {
for (int i = 0; i < 3; i++) {
dummy = values[i];
}
}
System.out.printf("Done in %.2f seconds.\n", (System.nanoTime() - t) / 1e9);
}
public static volatile Object dummy;
private static final MyEnumType2[] values = values();
}
I ran this on Java 8u60, on the Server VM. Each test using the values() method took around 10 seconds, while each test using the private array took around 2 seconds. Using the -verbose:gc JVM argument showed there was significant garbage collection activity when the values() method was used, and none when using the private array. Running the same tests on the Client VM, the private array was still fast, but the values() method became even slower, taking over a minute to finish. Calling values() also took longer the more enum constants were defined. All this indicates that the values() method really does allocate a new array each time, and that avoiding it can be advantageous.
Note that both java.util.EnumSet and java.util.EnumMap need to use the array of enum constants. For performance they call JRE proprietary code that caches the result of values() in a shared array stored in java.lang.Class. You can get access to that shared array yourself by calling sun.misc.SharedSecrets.getJavaLangAccess().getEnumConstantsShared(MyEnumType.class), but it is unsafe to depend on it as such APIs are not part of any spec and can be changed or removed in any Java update.
Conclusion:
The enum values() method has to behave as if it always allocates a new array, in case callers modify it.
Compilers or VMs could potentially optimize that allocation away in some cases, but apparently they don't.
In performance-critical code, it is well worth taking your own copy of the array.
I have written a same program in two different way and both are giving me different output. i am not able to understand why.
please correct me.
In first program i am getting this output
Original: Umesh
Changed: Xmesh
And in second program i am getting this output.
Original: Umesh
Changed: Umesh
Program-1
import java.lang.reflect.Field;
public class SomeClass {
public static void main(final String[] args) throws Throwable {
final String s = "Umesh";
changeString(s);
}
// We need a method so the compiler won't inline "s":
static void changeString(final String s) throws Throwable {
System.out.println("Original: " + s);
final Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
final char[] value = (char[]) field.get(s);
value[0] = 'X';
System.out.println("Changed: " + s);
}
}
Program-2
import java.lang.reflect.Field;
public class SomeClass {
public static void main(final String[] args) throws Throwable {
final String s = "Umesh";
System.out.println("Original: " + s);
final Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
final char[] value = (char[]) field.get(s);
value[0] = 'X';
System.out.println("Changed: " + s);
}
}
I'll just start by saying you really, really shouldn't be mucking about with strings like that. :-)
In your first example you aren't "re-referencing" anything (that is, you're not changing what string s refers to), what you're doing is modifying the string it refers to. Even though officially strings are immutable, you're using reflection as a backdoor to modify the undocumented internals of the String implementation in Oracle's JDK (other JDKs may be implemented differently, making that code fail). But the s reference is unchanged. Even with reflection, you can't change the value of a final local variable. (You could change a final field via reflection, but doing so would open you up to the same sort of inconsistencies you're seeing in this example.)
What's happening in your second example is that since s is a final variable you give a literal value to within main, as far as the compiler is concerned, it's a compile-time constant, since String is officially immutable. The compiler is (very) aware of strings and does a fair bit of optimization around them, such as turning "a" + "b" + "c" into simply "abc". So later, when it sees "Original: " + s, it can happily just substitute "Original: Umesh" for that. And again at the end, when it sees "Changed: " + s it can replace that with "Changed: Umesh". It ends up being exactly as though you'd actually written System.out.println("Original: Umesh"); and System.out.println("Changed: Umesh"); in the source code.
The compiler couldn't do that in the first example because s is an argument to the function, rather than a final declared right there in main.
You can see the difference in the bytecode. Compile each of them, then disassemble them via javac -p SomeClass. Here's what I get (I called them Example1 and Example2):
$ javap -c Example1
Compiled from "Example1.java"
public class Example1 {
public Example1();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]) throws java.lang.Throwable;
Code:
0: ldc #2 // String Umesh
2: invokestatic #3 // Method changeString:(Ljava/lang/String;)V
5: return
static void changeString(java.lang.String) throws java.lang.Throwable;
Code:
0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #5 // class java/lang/StringBuilder
6: dup
7: invokespecial #6 // Method java/lang/StringBuilder."":()V
10: ldc #7 // String Original:
12: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_0
16: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
25: ldc #11 // class java/lang/String
27: ldc #12 // String value
29: invokevirtual #13 // Method java/lang/Class.getDeclaredField:(Ljava/lang/String;)Ljava/lang/reflect/Field;
32: astore_1
33: aload_1
34: iconst_1
35: invokevirtual #14 // Method java/lang/reflect/Field.setAccessible:(Z)V
38: aload_1
39: aload_0
40: invokevirtual #15 // Method java/lang/reflect/Field.get:(Ljava/lang/Object;)Ljava/lang/Object;
43: checkcast #16 // class "[C"
46: checkcast #16 // class "[C"
49: astore_2
50: aload_2
51: iconst_0
52: bipush 88
54: castore
55: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
58: new #5 // class java/lang/StringBuilder
61: dup
62: invokespecial #6 // Method java/lang/StringBuilder."":()V
65: ldc #17 // String Changed:
67: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
70: aload_0
71: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
74: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
77: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
80: return
}
and
$ javap -c Example2
Compiled from "Example2.java"
public class Example2 {
public Example2();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
public static void main(java.lang.String[]) throws java.lang.Throwable;
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Original: Umesh
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: ldc #5 // class java/lang/String
10: ldc #6 // String value
12: invokevirtual #7 // Method java/lang/Class.getDeclaredField:(Ljava/lang/String;)Ljava/lang/reflect/Field;
15: astore_2
16: aload_2
17: iconst_1
18: invokevirtual #8 // Method java/lang/reflect/Field.setAccessible:(Z)V
21: aload_2
22: ldc #9 // String Umesh
24: invokevirtual #10 // Method java/lang/reflect/Field.get:(Ljava/lang/Object;)Ljava/lang/Object;
27: checkcast #11 // class "[C"
30: checkcast #11 // class "[C"
33: astore_3
34: aload_3
35: iconst_0
36: bipush 88
38: castore
39: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
42: ldc #12 // String Changed: Umesh
44: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
47: return
}
Notice how we don't see any string concatenation (StringBuilder usage) in the second example, the compiler combined the static strings at the compilation stage.
In the 2nd case, "Changed: " + s is a constant expression, the value is computed at compile time. It must be treated the same as the String literal "Changed: Umesh". (you can test that by ==)
In the 1st case, while aggressive optimzations are allowed on final fields , you are not actually modifying any final fields. You are writing to an array element, which is not final. This write must be visible to subsequent reads in the same thread.
This question is about interesting behavior of Java: it produces
additional (not default) constructor for nested classes in some
situations.
This question is also about strange anonymous class, which Java
produces with that strange constructor.
Consider the following code:
package a;
import java.lang.reflect.Constructor;
public class TestNested {
class A {
A() {
}
A(int a) {
}
}
public static void main(String[] args) {
Class<A> aClass = A.class;
for (Constructor c : aClass.getDeclaredConstructors()) {
System.out.println(c);
}
}
}
This will prints:
a.TestNested$A(a.TestNested)
a.TestNested$A(a.TestNested,int)
Ok. Next, lets make constructor A(int a) private:
private A(int a) {
}
Run program again. Receive:
a.TestNested$A(a.TestNested)
private a.TestNested$A(a.TestNested,int)
It is also ok. But now, lets modify main() method in such way (addition of new instance of class A creation):
public static void main(String[] args) {
Class<A> aClass = A.class;
for (Constructor c : aClass.getDeclaredConstructors()) {
System.out.println(c);
}
A a = new TestNested().new A(123); // new line of code
}
Then input becomes:
a.TestNested$A(a.TestNested)
private a.TestNested$A(a.TestNested,int)
a.TestNested$A(a.TestNested,int,a.TestNested$1)
What is it: a.TestNested$A(a.TestNested,int,a.TestNested$1) <<<---??
Ok, lets again make constructor A(int a) package local:
A(int a) {
}
Rerun program again (we don't remove line with instance of A creation!), output is as in the first time:
a.TestNested$A(a.TestNested)
a.TestNested$A(a.TestNested,int)
Questions:
1) How this could be explained?
2) What is this third strange constructor?
UPDATE: Investigation shown following.
1) Lets try to call this strange constructor using reflection from other class.
We will not able to do this, because there isn't any way to create instance of that strange TestNested$1 class.
2) Ok. Lets do the trick. Lets add to the class TestNested such static field:
public static Object object = new Object() {
public void print() {
System.out.println("sss");
}
};
Well? Ok, now we could call this third strange constructor from another class:
TestNested tn = new TestNested();
TestNested.A a = (TestNested.A)TestNested.A.class.getDeclaredConstructors()[2].newInstance(tn, 123, TestNested.object);
Sorry, but I absolutely don't understand it.
UPDATE-2: Further questions are:
3) Why Java use special anonymous inner class for an argument type for this third synthetic constructor? Why not just Object type, of constructor with special name?
4) What Java could use already defined anonymous inner class for those purposes? Isn't this some kind of violation of security?
The third constructor is a synthetic constructor generated by the compiler, in order to allow access to the private constructor from the outer class. This is because inner classes (and their enclosing classes' access to their private members) only exist for the Java language and not the JVM, so the compiler has to bridge the gap behind the scenes.
Reflection will tell you if a member is synthetic:
for (Constructor c : aClass.getDeclaredConstructors()) {
System.out.println(c + " " + c.isSynthetic());
}
This prints:
a.TestNested$A(a.TestNested) false
private a.TestNested$A(a.TestNested,int) false
a.TestNested$A(a.TestNested,int,a.TestNested$1) true
See this post for further discussion: Eclipse warning about synthetic accessor for private static nested classes in Java?
EDIT: interestingly, the eclipse compiler does it differently than javac. When using eclipse, it adds an argument of the type of the inner class itself:
a.TestNested$A(a.TestNested) false
private a.TestNested$A(a.TestNested,int) false
a.TestNested$A(a.TestNested,int,a.TestNested$A) true
I tried to trip it up by exposing that constructor ahead of time:
class A {
A() {
}
private A(int a) {
}
A(int a, A another) { }
}
It dealt with this by simply adding another argument to the synthetic constructor:
a.TestNested$A(a.TestNested) false
private a.TestNested$A(a.TestNested,int) false
a.TestNested$A(a.TestNested,int,a.TestNested$A) false
a.TestNested$A(a.TestNested,int,a.TestNested$A,a.TestNested$A) true
First of all, thank you for this interesting question. I was so intrigued that I could not resist taking a look at the bytecode. This is the bytecode of TestNested:
Compiled from "TestNested.java"
public class a.TestNested {
public a.TestNested();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc_w #2 // class a/TestNested$A
3: astore_1
4: aload_1
5: invokevirtual #3 // Method java/lang/Class.getDeclaredConstructors:()[Ljava/lang/reflect/Constructor;
8: astore_2
9: aload_2
10: arraylength
11: istore_3
12: iconst_0
13: istore 4
15: iload 4
17: iload_3
18: if_icmpge 41
21: aload_2
22: iload 4
24: aaload
25: astore 5
27: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
30: aload 5
32: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
35: iinc 4, 1
38: goto 15
41: new #2 // class a/TestNested$A
44: dup
45: new #6 // class a/TestNested
48: dup
49: invokespecial #7 // Method "<init>":()V
52: dup
53: invokevirtual #8 // Method java/lang/Object.getClass:()Ljava/lang/Class;
56: pop
57: bipush 123
59: aconst_null
60: invokespecial #9 // Method a/TestNested$A."<init>":(La/TestNested;ILa/TestNested$1;)V
63: astore_2
64: return
}
As you can see, the constructor a.TestNested$A(a.TestNested,int,a.TestNested$1) is invoked from your main method. Furthermore, null is passed as the value of the a.TestNested$1 parameter.
So let's take a look at the mysterious anonymous class a.TestNested$1:
Compiled from "TestNested.java"
class a.TestNested$1 {
}
Strange - I would have expected this class to actually do something. To understand it, let's take a look at the constructors in a.TestNested$A:
class a.TestNested$A {
final a.TestNested this$0;
a.TestNested$A(a.TestNested);
Code:
0: aload_0
1: aload_1
2: putfield #2 // Field this$0:La/TestNested;
5: aload_0
6: invokespecial #3 // Method java/lang/Object."<init>":()V
9: return
private a.TestNested$A(a.TestNested, int);
Code:
0: aload_0
1: aload_1
2: putfield #2 // Field this$0:La/TestNested;
5: aload_0
6: invokespecial #3 // Method java/lang/Object."<init>":()V
9: return
a.TestNested$A(a.TestNested, int, a.TestNested$1);
Code:
0: aload_0
1: aload_1
2: iload_2
3: invokespecial #1 // Method "<init>":(La/TestNested;I)V
6: return
}
Looking at the package-visible constructor a.TestNested$A(a.TestNested, int, a.TestNested$1), we can see that the third argument is ignored.
Now we can explain the constructor and the anonymous inner class. The additional constructor is required in order to circumvent the visibility restriction on the private constructor. This additional constructor simply delegates to the private constructor. However, it cannot have the exact same signature as the private constructor. Because of this, the anonymous inner class is added to provide a unique signature without colliding with other possible overloaded constructors, such as a constructor with signature (int,int) or (int,Object). Since this anonymous inner class is only needed to create a unique signature, it does not need to be instantiated and does not need to have content.
Inside a Java enumerated class, I'd like to create a final static array containing the values() of the class. When I do this along the following lines, the resulting array is null.
public enum Name {
E1( stuff ), E2( stuff );
private static final Name[] values = Name.values();
private Name( stuff ) { more stuff; }
}
I've also tried doing this by calling an explicit class setter method, but this gave an java.lang.ExceptionInInitializerError exception.
I understand the problem is caused by some shallow dependencies as the stuff in the previous code uses other classes, which themselves depend on the enumerated class.
Is there a tested and proven technique to achieve what I need?
tl;dr: what you're trying to do isn't possible - static fields of an enum type don't get initialized until after all the constructor calls have completed.
Consider this example:
public enum Name {
E1("hello"), E2("world");
private static final Name[] values = values();
private Name(String val) {
System.out.println("val = " + val);
dump();
}
protected void dump() {
System.out.println("this = " + this + ", values = " + values);
}
}
Note that the reason for the existence of the dump method is that it is a compile-time error (Java Language Spec section 8.9.2) to try and reference the value field from inside the constructor of Name. With this test harness:
public class Main {
public static void main(String... args) throws Exception {
System.out.println(Name.values());
}
}
we get
$ java Main
val = hello
this = E1, values = null
val = world
this = E2, values = null
[LName;#35960f05
Decompiling the Name class with javap we see the following:
private static final Name[] $VALUES;
public static Name[] values();
Code:
0: getstatic #1; //Field $VALUES:[LName;
3: invokevirtual #2; //Method "[LName;".clone:()Ljava/lang/Object;
6: checkcast #3; //class "[LName;"
9: areturn
The compiler creates a private field $VALUES holding the value array, and the values() method is implemented as { return (Name[])$VALUES.clone() }. So how does $VALUES get initialized?
static {};
Code:
0: new #4; //class Name
3: dup
4: ldc #19; //String E1
6: iconst_0
7: ldc #20; //String hello
9: invokespecial #21; //Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
12: putstatic #22; //Field E1:LName;
15: new #4; //class Name
18: dup
19: ldc #23; //String E2
21: iconst_1
22: ldc #24; //String world
24: invokespecial #21; //Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
27: putstatic #25; //Field E2:LName;
30: iconst_2
31: anewarray #4; //class Name
34: dup
35: iconst_0
36: getstatic #22; //Field E1:LName;
39: aastore
40: dup
41: iconst_1
42: getstatic #25; //Field E2:LName;
45: aastore
46: putstatic #1; //Field $VALUES:[LName;
49: invokestatic #26; //Method values:()[LName;
52: putstatic #18; //Field values:[LName;
55: return
}
What we see here is that the initialization essentially does:
// compiler-generated initialization code
E1 = new Name("hello");
E2 = new Name("world");
$VALUES = new Name[] {E1, E2};
// static initializer of the values field
values = Name.values();
so during the execution of the constructor calls, the values field will be null and the values() method will throw a NullPointerException (which will get wrapped in an ExceptionInInitializerError).
Can you provide an example where this happens because it shouldn't be null.
public class Main {
public enum Name {
E1( ), E2( );
private static final Name[] VALUES = Name.values();
}
public static void main(String... args) {
System.out.println(Name.VALUES);
System.out.println(Arrays.asList(Name.VALUES));
}
}
prints
[LMain$Name;#717e5fde
[E1, E2]