5

I often find code which uses generics in Java like this:

public static <T extends Object & Interface> foo(T object) {
    ...
}

Since in Java every class inherites from object class I'm not sure if extends Object gives a special meaning or is used for special purposes. Can anyone tell me if there is a different background using this or this is implicit given when you take <T extends Interface>?

Julian L.
  • 401
  • 4
  • 12
  • 3
    I'm curious, where do you "often" find this code? – Tunaki Sep 26 '15 at 10:12
  • 1
    Please provide an *exact* signature of the method, not artificial example. Your `foo` lacks the return type and will not compile. Also I have strong feeling that the argument was not just `T`, but something like `List`. It would also be nice if you point where you saw such method. I think I can answer why it's necessary, but I need the exact details. – Tagir Valeev Sep 26 '15 at 10:33
  • @TagirValeev You are not right. It was only T. I found this example in the book "Der Weg zum Java-Profi" by Michael Inden. Of course there is a return statement in the original code. My question was only concerning the tag. But thanks anyway. – Julian L. Sep 26 '15 at 10:42
  • @Tunaki See my last comment. But I saw it more often in some codes from projects of my student colleagues and wondered if this is redundant or not. – Julian L. Sep 26 '15 at 10:44
  • @JulianL., ok, I don't know what was the reason in your book, but I posted the case when it can be reasonable. – Tagir Valeev Sep 26 '15 at 11:03

3 Answers3

5
<T extends Object & Interface>

That Object is clearly redundant and typically equals to

<T extends Interface>

Note that using Interface as a class name is highly discouraged.

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • Why is it highly discouraged? Just curios. SomeClass.Interface is used in our projects and it works just fine. – mjs Sep 26 '15 at 10:20
  • @momo There is already a key word called `interface` is there, so people may confuse and A real class never be an `Interface` :). Coming to your code, `SomeClass.Interface`, what is `Interface` there ? – Suresh Atta Sep 26 '15 at 10:23
  • Thanks for your reply. This was not code from my projects, the interface name was only one example. – Julian L. Sep 26 '15 at 10:40
  • 1
    @JulianL. If that is the case, there is no need of that last note in my answer :) Happy coding. – Suresh Atta Sep 26 '15 at 10:41
  • @sᴜʀᴇsʜᴀᴛᴛᴀ The Interface represents teh interface of SomeClass. For instance, Vehicle.Interface would represent the Interface of vehicle. Ratehr than naming it VehicleInterface and place it in the same package, I find it neater to just place it inside Vechile and calling it Interface. – mjs Sep 27 '15 at 09:10
3

This may be necessary to make your code backwards-compatible on binary level. Suppose that you have the following utility class:

public class Utils {
    public static <T> int length(T obj) {
        if(obj instanceof CharSequence) {
            return ((CharSequence)obj).length();
        }
        return 0;
    }
}

It's published as a library and used in some applications like this:

public class Main {
    public static void main(String... args) {
        System.out.println(Utils.length("foo"));
    }
}

Works fine. However later you decided that it's good to limit your method only to implementations of some interface CharSequence as for other objects it always returns 0 anyways and seems that nobody uses your method with non-CharSequence parameter. So you change the signature to

public static <T extends CharSequence> int length(T obj) { ... }

Now if you link the Main class with new version of your library, it will fail with java.lang.NoSuchMethodError. That's because the erased signature of your method changed. Before it was int length(Object obj), but now it's int length(CharSequence obj). If you recompile the Main class, it will work fine, but it's not always possible to recompile all the existing code. Thus the trick could be performed:

public static <T extends Object & CharSequence> int length(T obj) { ... }

Now you're actually limiting the parameter to CharSequence interface, but the erased signature is back to int length(Object obj) (the erased type is always the first in the chain of A & B & C & ..., it's officially documented), so the new version of Utils class is binary compatible with the old code.

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
0

As you noted, any T would implicitly extend Object anyway. Explicitly defining T extends Object is completely redundant, and you could (and probably should) remove it, and just define T extends Interface.

Mureinik
  • 297,002
  • 52
  • 306
  • 350