I have some legacy code with class Box
to put and get Serializable
data into a Map
, which runs fine on Oracle JRE 1.8 Update 102
when compiled with Oracle JDK 1.7 Update 80
. But it don't run properly when I compile it with Oracle JDK 1.8 Updater 102
. I had some problems with a generic get
function.
A SSCCE which outputs a formatted date from a Box
instance using a problematic generic get
function:
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
public class Box implements Serializable{
private HashMap<String, Serializable> values = new HashMap<String, Serializable>();
public <T extends Serializable> T get(String key){
return (T) this.values.get(key);
}
public void put(String key,
Serializable value){
this.values.put(key,
value);
}
public static void main(String[] args){
Box box = new Box();
box.put("key",
new Date());
System.out.println(String.format("%1$td.%1$tm.%1$tY",
box.get("key")));
}
}
I get the following exception when it is compiled with JDK 1.8 and I run it with JRE 1.8:
Exception in thread "main" java.lang.ClassCastException: java.util.Date cannot be cast to [Ljava.lang.Object; at Box.main(Box.java:31)
Some Methods like System.out.println produces a compiler error when used with the get
function
error: reference to println is ambiguous
while other function runs fine with the get
function.
The compiler prints out a warning about unchecked or unsafe operations
and I noticed the main method is compiled to different byte code:
Compiled with 1.7:
public static void main(java.lang.String[]);
Code:
0: new #8 // class Box
3: dup
4: invokespecial #9 // Method "<init>":()V
7: astore_1
8: aload_1
9: ldc #10 // String key
11: new #11 // class java/util/Date
14: dup
15: invokespecial #12 // Method java/util/Date."<init>":()V
18: invokevirtual #13 // Method put:(Ljava/lang/String;Ljava/io/Serializable;)V
21: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;
24: ldc #15 // String %1$td.%1$tm.%1$tY
26: iconst_1
27: anewarray #16 // class java/lang/Object
30: dup
31: iconst_0
32: aload_1
33: ldc #10 // String key
35: invokevirtual #17 // Method get:(Ljava/lang/String;)Ljava/io/Serializable;
38: aastore
39: invokestatic #18 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
42: invokevirtual #19 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
45: return
Compiled with 1.8:
public static void main(java.lang.String[]);
Code:
0: new #8 // class Box
3: dup
4: invokespecial #9 // Method "<init>":()V
7: astore_1
8: aload_1
9: ldc #10 // String key
11: new #11 // class java/util/Date
14: dup
15: invokespecial #12 // Method java/util/Date."<init>":()V
18: invokevirtual #13 // Method put:(Ljava/lang/String;Ljava/io/Serializable;)V
21: getstatic #14 // Field java/lang/System.out:Ljava/io/PrintStream;
24: ldc #15 // String %1$td.%1$tm.%1$tY
26: aload_1
27: ldc #10 // String key
29: invokevirtual #16 // Method get:(Ljava/lang/String;)Ljava/io/Serializable;
32: checkcast #17 // class "[Ljava/lang/Object;"
35: invokestatic #18 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
38: invokevirtual #19 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
41: return
Can somebody explain why it is compiled differently?
PS: I already fixed it by giving Class<T> clazz
as additional parameter to the get
function.