I found a piece of code that after switching from Java 7 to Java 8 stopped compiling. It does not feature any of the new Java 8 stuff like lambda or streams.
I narrowed
Have to claim this is not an answer, merely a reasoning. With my brief experience in compiler (not Javac specific), it could has something to do with how the code is parsed.
In the following decompiled code, you see either calling the method GenericData.getData:()Ljava/lang/Object
or referring to field GenericData.data:Ljava/lang/Object
, they both first get the value/method with Object returned, followed by a cast
.
stack=4, locals=4, args_size=1
0: new #2 // class general/GenericData
3: dup
4: dconst_1
5: invokestatic #3 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
8: invokespecial #4 // Method general/GenericData."":(Ljava/lang/Object;)V
11: astore_1
12: aload_1
13: ifnonnull 23
16: dconst_0
17: invokestatic #3 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
20: goto 30
23: aload_1
24: invokevirtual #5 // Method general/GenericData.getData:()Ljava/lang/Object;
27: checkcast #6 // class java/lang/Double
30: astore_2
31: aload_1
32: ifnonnull 39
35: dconst_0
36: goto 49
39: aload_1
40: getfield #7 // Field general/GenericData.data:Ljava/lang/Object;
43: checkcast #6 // class java/lang/Double
46: invokevirtual #8 // Method java/lang/Double.doubleValue:()D
49: invokestatic #3 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
52: astore_3
53: return
If compare the ternary operator expression with an equivalent if-else:
Integer v = 10;
v = v != null ? 1 : 0;
0: bipush 10
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: aload_1
7: ifnull 14
10: iconst_1
11: goto 15
14: iconst_0
15: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
18: astore_1
19: return
Integer v = 10;
if (v != null)
v = 1;
else
v = 0;
0: bipush 10
2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: aload_1
7: ifnull 18
10: iconst_1
11: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
14: astore_1
15: goto 23
18: iconst_0
19: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
22: astore_1
23: return
There is no significant difference in the two versions. So I don't think there is a hidden secret doing all the black magic. It's a result of how the compiler parse the whole expression, and based on the context to figure out a type to make all components equally happy. E.g.,
Double val = 0; // compilation error: context is clear, 0 is an integer, so Integer.valueOf(i), but don't match expected type - Double
val = 0 + g.getData(); // OK, enough context to figure out the type should be Double
Still, the confusion is in that why the generic field works but not the generic method...
val = val == null ? 0 : g.data; // OK
val = val == null ? 0 : g.getData(); // Compilation error
EDIT: the document Holger quoted seems to be a good clarification.