14

Have a look at this (arguably stupid) code:

public <T extends Appendable & Closeable> void doStuff(T object)
throws IOException{

    object.append("hey there");
    object.close();

}

I know that the compiler removes generic information, so I'm interested in Java 1.4 code equivalent to what the compiler does (I'm pretty sure the compiler doesn't rearrange the source code, so I am asking for an equivalent Java source version which naive people like myself can understand)

Is is something like this:

public void doStuff(Object object)
throws IOException{

    ((Appendable)object).append("hey there");
    ((Closeable)object).close();

}

Or rather like this:

public void doStuff(Object object)
throws IOException{
    Appendable appendable = (Appendable) object;
    Closeable closeable = (Closeable) object;

    appendable.append("hey there");
    closeable.close();

}

Or even like this:

public void doStuff(Appendable appendable)
throws IOException{
    Closeable closeable = (Closeable) appendable;

    appendable.append("hey there");
    closeable.close();

}

Or yet another version?

2
  • why don't you decompile the code with javap to find out. I suspect this is not definied and different compilers could handle it differently. Commented Nov 23, 2010 at 16:41
  • I might do that, but I was hoping for real answers from smart people who explain to me why things are what they are. Commented Nov 23, 2010 at 16:43

2 Answers 2

14

Signature of the method looks like public void doStuff(Appendable appendable), because

The order of types in a bound is only significant in that the erasure of a type variable is determined by the first type in its bound, and that a class type or type variable may only appear in the first position.

(JLS §4.4 Type Variables)

This behaviour may be important if you use reflection to access this method.

Another use of this behaviour is retaining binary compatibility with pre-generic interfaces, as described in Generics Tutorial, section 10 (thanks to Mark Peters for pointing it out). That is,

public static <T extends Object & Comparable<? super T>> T max(Collection<T> coll)

is binary compatible with its pre-generic version returning Object.


Method body is an equivalent of the following, but I think it's implementation details:

appendable.append("hey there"); 
((Closeable) appendable).close(); 
3
  • 3
    +1, you might also look at the Generics Tutorial, section 10 (java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf) which examines the case of Collections.max(). max() uses the multiple bounds <T extends Object & Comparable<? super T>> to retain binary compatibility after being retrofitted with Generics. Commented Nov 23, 2010 at 16:56
  • @Mark Peters or you should just undelete your own answer. What's wrong with it? Commented Nov 23, 2010 at 17:08
  • @seanizer: axtavt beat me to saying the same thing, and the JLS is more authoritative than a tutorial. I figured two answers saying exactly the same thing but with different citations wasn't productive. @axtavt is free to include that in his answer if he choses. Commented Nov 23, 2010 at 18:23
4

I couldn't wait, I had to go and answer my own question. The answer is a combination of my first and third versions: the first bound is used as variable type, and the object is casted to the second bound whenever needed. This is the resulting byte code (I added a single line break for readability):

  // Method descriptor #20 (Ljava/lang/Appendable;)V
  // Signature: <T::Ljava/lang/Appendable;:Ljava/io/Closeable;>(TT;)V
  // Stack: 2, Locals: 2
  public void doStuff(java.lang.Appendable object) throws java.io.IOException;
     0  aload_1 [object]
     1  ldc <String "hey there"> [26]
     3  invokeinterface java.lang.Appendable.append(java.lang.CharSequence) :
        java.lang.Appendable [28] [nargs: 2]
     8  pop
     9  aload_1 [object]
    10  checkcast java.io.Closeable [34]
    13  invokeinterface java.io.Closeable.close() : void [36] [nargs: 1]
    18  return
      Line numbers:
        [pc: 0, line: 14]
        [pc: 9, line: 15]
        [pc: 18, line: 17]
      Local variable table:
        [pc: 0, pc: 19] local: this index: 0 type: rumba.dumba.Bumba
        [pc: 0, pc: 19] local: object index: 1 type: java.lang.Appendable
      Local variable type table:
        [pc: 0, pc: 19] local: object index: 1 type: T
2
  • Cool! But may I suggest you to use java decompiler next time for readability? :)
    – AlexR
    Commented Nov 23, 2010 at 19:35
  • Good idea, but I'm lazy, and I just had to open the class file in eclipse, so I went for that Commented Nov 23, 2010 at 22:44

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.