Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generics: Special usage <T extends Object & Interface>

Tags:

java

generics

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>?

like image 621
Julian L. Avatar asked Sep 26 '15 10:09

Julian L.


People also ask

What is the difference between list <? Extends T and list <? Super T >?

super is a lower bound, and extends is an upper bound.

What is <? Super T in Java?

super T denotes an unknown type that is a supertype of T (or T itself; remember that the supertype relation is reflexive). It is the dual of the bounded wildcards we've been using, where we use ? extends T to denote an unknown type that is a subtype of T .

What is E and T in Java generics?

T is meant to be a Type. E is meant to be an Element ( List<E> : a list of Elements) K is Key (in a Map<K,V> ) V is Value (as a return value or mapped value)

What does T stand for in Java generics?

In Java there's a single metaclass: Class . Its instances (only one per type exists) are used to represent classes and interfaces, therefore the T in Class<T> refers to the type of the class or interface that the current instance of Class represents.


2 Answers

<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.

like image 122
Suresh Atta Avatar answered Oct 05 '22 12:10

Suresh Atta


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.

like image 37
Tagir Valeev Avatar answered Oct 05 '22 12:10

Tagir Valeev