Java Insanity: Two methods with the same super.method()
Overview
Recently I wrote an article on how you could write multiple methods with the same name and parameters by using generics. I wondered if you can have multiple methods with the same super.method()Generics and signatures
The way the Java compiler works, the generic is effectively part of the signature. However, due to type erasure, the JVM doesn't care so how can this work? The answer is that for the JVM the return type is part of the signature. This means if you have two method with different generic signatures and return types they can have the same name and parameter types.For the purposes of determining a parent super.method(), they share the same method. So if you have two methods overriding a method, which one is actually called. The answer is neither, polymorphism breaks and the parent still gets called.
static class A { public Number method() { System.out.println("Inside: Number A.method()"); return 0; } } static class B extends A { public <T extends Integer> T method() { System.out.println("Inside: Integer B.method()"); super.method(); return (T) (Integer) 0; } public <T extends Long> T method() { System.out.println("Inside: Long B.method()"); super.method(); return (T) (Long) 0L; } } public static void main(String... args) { B b = new B(); b.<Integer>method(); System.out.println("============="); b.<Long>method(); System.out.println("============="); A a = b; a.method(); }
prints
Inside: Integer B.method() Inside: Number A.method() ============= Inside: Long B.method() Inside: Number A.method() ============= Inside: Number A.method()
The byte code
For anyone who doubts this even compiles here is the byte code for your interest.Main byte code
$ javap -c -classpath . Main Compiled from "Main.java" public class Main extends java.lang.Object{ public Main(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2; //class Main$B 3: dup 4: invokespecial #3; //Method Main$B." ":()V 7: astore_1 8: aload_1 9: invokevirtual #4; //Method Main$B.method:()Ljava/lang/Integer; 12: pop 13: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream; 16: ldc #6; //String ============= 18: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 21: aload_1 22: invokevirtual #8; //Method Main$B.method:()Ljava/lang/Long; 25: pop 26: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream; 29: ldc #6; //String ============= 31: invokevirtual #7; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 34: aload_1 35: astore_2 36: aload_2 37: invokevirtual #9; //Method Main$A.method:()Ljava/lang/Number; 40: pop 41: return }
Main.A byte code
$ javap -c -classpath . Main\$A Compiled from "Main.java" class Main$A extends java.lang.Object{ Main$A(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public java.lang.Number method(); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Inside: Number A.method() 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: iconst_0 9: invokestatic #5; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 12: areturn }
Main.B byte code
You can see on line 9 of each method that they call the same parent class.$ javap -c -classpath . Main\$B Compiled from "Main.java" class Main$B extends Main$A{ Main$B(); Code: 0: aload_0 1: invokespecial #1; //Method Main$A."":()V 4: return public java.lang.Integer method(); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String Inside: Integer B.method() 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: aload_0 9: invokespecial #5; //Method Main$A.method:()Ljava/lang/Number; 12: pop 13: iconst_0 14: invokestatic #6; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 17: areturn public java.lang.Long method(); Code: 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #7; //String Inside: Long B.method() 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: aload_0 9: invokespecial #5; //Method Main$A.method:()Ljava/lang/Number; 12: pop 13: lconst_0 14: invokestatic #8; //Method java/lang/Long.valueOf:(J)Ljava/lang/Long; 17: areturn }
Interesting... But if I use Eclipse for compilation I get error 'Duplicate method method() in type test.B'. If i use javac for compilation it is good!
ReplyDelete@mmashnitsky, IntelliJ complains as well, but compiles it fine (with the Sun/Oracle javac)
ReplyDeleteThanks for interesting articles!
ReplyDeleteThis is nice post. It is really beneficial for me. Here I have got another link on super method in java, this link is also beneficial... that link is..
ReplyDeletehttp://mindstick.com/Blog/252/Super%20method%20in%20java
Thanks
@Memtech, When posting code, you should try to ensure it compiles. Posting pseudo code isn't as useful. ;)
ReplyDelete