I can't see why size(test); won't compile. Can someone help me understand?
public class TestContainer<T extends Object> {
}
.
public class Main {
public static int size(List<TestContainer<?>> list) {
return list.size();
}
public static void main(String[] args) {
List<TestContainer<Object>> test = new ArrayList<TestContainer<Object>>();
size(test); // this does not compile
test.size(); // of course this works fine
}
}
List<TestContainer<Object>> is not a List<TestContainer<?>>.
A TestContainer<Integer> is a TestContainer<?>. Therefore, you can add a TC<Integer> to a List<TC<?>>. Similarly, you can add a TC<String> to a List<TC<?>>.
However, a TC<Integer> is not a TC<Object> (because generics are invariant in Java), so you mustn't be allowed to add a TC<Integer> to a List<TC<Object>>. As such, a List<TC<Object>> isn't a List<TC<?>>.
If you make it so that you are unable to add anything (except literal null) to the List - by making the method parameter List<? extends TC<?>> (or List<?>, if you are really uninterested in the elements) - it is safe, and thus allowed.
A method with as parameter a generic List can accept subclasses of the generic type only if the List parameter declaration is parameterized with an upper bounded wildcard.
You don't declare any upper bounded wildcard (<? extend T>) for List<TestContainer> here :
public static int size(List<TestContainer<?>> list) {
return list.size();
}
So you can only pass this exact type as parameter :
List<TestContainer<?>>
To achieve you want, you should so write :
public static int size(List<? extends TestContainer<?>> list) {
return list.size();
}
Note that the upper bounded wildcard is designed to ensure the type safety of the passed List.
As a consequence, inside the method, you could not add anything in but null.
But for your use case (returning the size of the list), it is not a problem.
Related
As far as I know, using an upper bounded generic and using a superclass as a method parameter both accept the same possible arguments. Which is preferred, and what's the difference between the two, if any?
Upper bounded generic as parameter:
public <T extends Foo> void doSomething(T foo) {}
Superclass as parameter:
public void doSomething(Foo foo) {}
That's an upper bounded type parameter. Lower bounds are created using super, which you can't really do for a type parameter. You can't have a lower bounded type parameter.
And that would make a difference, if you, for example want to pass a List<T>. So, for the below two methods:
public <T extends Foo> void doSomething(List<T> foos) {}
public void doSomething(List<Foo> foo) {}
And for the given class:
class Bar extends Foo { }
The following method invocation:
List<Bar> list = new ArrayList<Bar>();
doSomething(list);
is valid for 1st method, but not for 2nd method. 2nd method fails because a List<Foo> is not a super type of List<Bar>, although Foo is super type of Bar. However, 1st method passes, because there the type parameter T will be inferred as Bar.
Generally, you only need a type variable when it's used in more than one place in class/method/field declarations. When you declare one on a method (rather than a class), the only places to use it are on the parameters and return value of that method.
For example, you can use it on multiple parameters to ensure their types match:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
This is a trivial example, but you can see that it prevents you from giving it an element that doesn't match the list's generic type:
List<Integer> list = new ArrayList<>();
addToList(list, 7);
//addToList(list, 0.7); // doesn't compile
//addToList(list, "a"); // doesn't compile
You can also declare a parameter and the return type to be the same type:
public static <T> T nullCheck(T value, T defValue) {
return value != null ? value : defValue;
}
Since this method is returning one of the two T objects it's given, we can safely say that the returned object is also of type T.
Integer iN = null;
Integer i = nullCheck(iN, 7);
System.out.println(i); // "7"
Double dN = null;
Double d = nullCheck(dN, 0.7);
System.out.println(d); // "0.7"
Number n = nullCheck(i, d); // T = superclass of Integer and Double
System.out.println(n); // "7"
As for the example in the question, the type variable is only being used once, so it's equivalent to using the superclass. In this case you should avoid declaring a type variable, it's just unnecessary clutter.
Also I should note that the other answer changes the example to use List<T> and List<Foo>, but as mentioned in the comments, the superclass is really List<? extends Foo>, so no type variable is needed there, either.
I am new to Java. In this document they give this as a use case for using wildcard:
static void printCollection(Collection c) {
Iterator i = c.iterator();
for (int k = 0; k < c.size(); k++) {
System.out.println(i.next());
}
}
This is their solution:
static void printCollection(Collection<?> c) {
for (Object e : c) {
System.out.println(e);
}
}
But I could do the same without a wild card:
static <T> void printCollection(Collection<T> c) {
Iterator i = c.iterator();
for (int k = 0; k < c.size(); k++) {
System.out.println(i.next());
}
}
Can someone show me a simple use case where regular generics won't work but a wild card will?
Update: The answers over here When to use wildcards in Java Generics? do NOT tell us the need for wildcard. In fact its the other way around.
One thing wildcards allow us to do is declare types that are agnostic towards a particular type parameter, for example a "list of any kind of list":
List<List<?>> listOfAnyList = ...;
listOfAnyList.add( new ArrayList<String>() );
listOfAnyList.add( new ArrayList<Double>() );
This is impossible without a wildcard:* because the element lists may have different types from each other.
And if we try to capture it, we will find that we can't:
static <E> void m(List<List<E>> listOfParticularList) {}
m( listOfAnyList ); // <- this won't compile
Another thing wildcards allow us to do that type parameters cannot is set a lower bound. (A type parameter can be declared with an extends bound, but not a super bound.**)
class Protector {
private String secretMessage = "abc";
void pass(Consumer<? super String> consumer) {
consumer.accept( secretMessage );
}
}
Suppose pass was instead declared to take a Consumer<String>. Now suppose we had a Consumer<Object>:
class CollectorOfAnything implements Consumer<Object> {
private List<Object> myCollection = new ArrayList<>();
#Override
public void accept(Object anything) {
myCollection.add( anything );
}
}
The problem is: we can't pass it to a method accepting Consumer<String>. Declaring Consumer<? super String> means that we can pass any consumer which accepts a String. (Also see Java Generics: What is PECS?.)
Most of the time, wildcards just let us make tidy declarations.
If we don't need to use a type, we don't have to declare a type parameter for it.
* Technically also possible with a raw type, but raw types are discouraged.
** I don't know why Java doesn't allow super for a type parameter. 4.5.1. Type Arguments of Parameterized Types may hint that it has something to do with a limitation of type inference:
Unlike ordinary type variables declared in a method signature, no type inference is required when using a wildcard. Consequently, it is permissible to declare lower bounds on a wildcard […].
T stands for the generic type of that data structure. In your last example, you don't use it, and its NOT an actual type (for example String), and because you don't use it it doesn't really matter in this case.
For example, if you had a Collection and tried to pass it to a method that accepts a Collection, that works because there is no type T on the classpath so its considered a variable. If you tried passing the same Collection to a method that accepts a Collection, that would not work because you have String on your classpath so its not a variable.
Take List as the example.
List<?> can be the parent class of List<A>.
for instance,
List<B> bList = new ArrayList<>(); // B is a class defined in advance
List<?> list = bList;
you can never use <T> in this situation.
<?> has the wildcard capture.
here,
void foo(List<?> i) {
i.set(0, i.get(0));
}
the code above cannot be compiled. You can fix it:
void foo(List<?> i) {
fooHelper(i);
}
// wildcard can be captured through type inference.
private <T> void fooHelper(List<T> l) {
l.set(0, l.get(0));
}
see more, http://docs.oracle.com/javase/tutorial/java/generics/capture.html
I can only think of the two currently, later may update.
What is the purpose of using a wildcard for unbounded or upper-bounded generics? More specifically:
Why would I say public static void foo(List<?> bar) instead of public static <E> void foo(List<E> bar)?
Why would I say public static void foo(List<? extends Baz> bar) instead of public static <E extends Baz> void foo(List<E> bar)?
If you are not ever going to refer to E in the code that follows, there is no need to declare it.
Reduces programmer memory strain.
The versions with a wildcard are preferred. If a parameter has type List<?> it is clear that any List will be accepted. If any List is accepted, there's no reason to give the type parameter a name, so writing <E> would just be clutter. On the other hand, if the type parameter appears twice in the signature, then you cannot use wildcards. For example, this signature needs a type parameter.
public static <E> List<E> combineLists(List<E> list1, List<E> list2)
Actually in that example it would probably be better if the arguments had type List<? extends E> (the only way to do that without wildcards would be to have three type parameters, a total mess).
In Effective Java, it is recommended that even if the type parameter is needed in the body of the method, you should prefer the version of the signature with a wildcard, and write a private helper method to make this possible. For example:
public static void swapFirstAndLast(List<?> list) {
helper(list);
}
private static <E> void helper(List<E> list) {
int size = list.size();
E e = list.get(0);
list.set(0, list.get(size - 1)); // These lines would not be possible
list.set(size - 1, e); // If the type of list were List<?>
}
If the type of the list is decided at runtime, then you will need to use wildcards.
The following program will print a List<String> if run with any command-line arguments; otherwise it will print a List<Number>:
public class Test {
public static List<String> listOfStrings = Arrays.asList("hello", "world");
public static List<Number> listOfNumbers = Arrays.asList(1, 2, 3, 4.5);
public static List<?> getListOfUnknown(boolean arg) {
if(arg) return listOfStrings;
else return listOfNumbers;
}
public static void main(String[] args) {
System.out.println(getListOfUnknown(args.length > 0));
}
}
The official tutorial for generic method already explained well enough.
... the type parameter T is used only once. The return type doesn't depend on the type parameter, nor does any other argument to the method (in this case, there simply is only one argument). This tells us that the type argument is being used for polymorphism; its only effect is to allow a variety of actual argument types to be used at different invocation sites. If that is the case, one should use wildcards. ...
Generic methods allow type parameters to be used to express dependencies among the types of one or more arguments to a method and/or its return type. If there isn't such a dependency, a generic method should not be used.
Suppose I have a method:
public class AwesomeClass {
public <E> List<E> convertIterableToList(Iterable<E> iterable) {
...
}
}
At runtime, how can I resolve the method's return type based on the argument type? For example, I wish to implement a hypothetical method resolveReturnType whose behavior is demonstrated in this little (pseudo-Java) unit test:
Method method = AwesomeClass.class.getDeclaredMethod("convertIterableToList", Iterable.class);
Type argumentType = {{{Set<String>}}}; // Just pretend this syntax works. :)
Type expectedReturnType = {{{List<String>}}};
Type actualReturnType = resolveReturnType(method, argumentType);
assertEquals(expectedReturnType, actualReturnType);
So far, I have been trying to use Guava's TypeToken class but I have been not making much progress.
So, this is actually possible, provided that you have the actual formal Types of the arguments to the method available. As #JvR notes, this isn't possible in general at runtime, but if (as in your example) you are able to explicitly specify those types using TypeToken or some such, it does work.
static Type resolveReturnType(Type classType, Method method, Type... argTypes) {
// this should resolve any class-level type variables
Type returnType = TypeToken.of(classType)
.resolveType(method.getGenericReturnType()).getType();
Type[] parameterTypes = method.getGenericParameterTypes();
TypeResolver resolver = new TypeResolver();
for (int i = 0; i < parameterTypes.length; i++) {
#SuppressWarnings("unchecked") // necessary for getSupertype call to compile
TypeToken<Object> paramType =
(TypeToken<Object>) TypeToken.of(parameterTypes[i]);
#SuppressWarnings("unchecked") // necessary for getSupertype call to compile
TypeToken<Object> argType =
(TypeToken<Object>) TypeToken.of(argTypes[i]);
if (method.isVarArgs() && i == parameterTypes.length - 1) {
// TODO
} else {
TypeToken<?> argTypeAsParamType =
argType.getSupertype(paramType.getRawType());
resolver = resolver.where(
paramType.getType(), argTypeAsParamType.getType());
}
}
return resolver.resolveType(returnType);
}
There are some holes in the above code: for example, it won't resolve the return type of E foo(E[] array) correctly given an argument type of String[]. It also can't help with any generic method whose return type has a type variable that is not used in its parameter types, of course. I also haven't tried it with various other things, like wildcards. But for your example it works, and it also handles type variables declared by the class (if it's an instance method) in addition to those declared by the method:
public class Foo<T> {
public <E> Map<T, E> convertIterableToMap(Iterable<E> iterable) {
return null;
}
public static void main(String[] args) throws Exception {
Method method = Foo.class.getMethod("convertIterableToMap", Iterable.class);
Type instanceType = new TypeToken<Foo<Integer>>() {}.getType();
Type setOfString = new TypeToken<Set<String>>() {}.getType();
// prints: java.util.Map<java.lang.Integer, java.lang.String>
System.out.println(resolveReturnType(instanceType, method, setOfString));
}
}
Short answer: you can't.
Longer answer:
<E> List<E> convertIterableToList(Iterable<E> iterable) has a type E that is not generally reifiable. You could check whether the supplied iterable has fixed this type (1) in its class definition, which means you could retrieve that and figure out what E means in that specific invocation.
But in the general case, the runtime won't know what E is for any specific invocation.
(1) Meaning something like class StringList implements List<String> where the type variable is fixed.
Given some class SomeBaseClass, are these two method declarations equivalent?
public <T extends SomeBaseClass> void myMethod(Class<T> clz)
and
public void myMethod(Class<? extends SomeBaseClass> clz)
For the caller: yes, they are equivalent.
For the code inside the method: no.
The difference is that within the code of the first example you can use the type T (for example to hold an object created by clz.newInstance()), while in the second you can't.
No, they're not. With the first definition, you can use the type T inside the method definition, e.g. create an ArrayList<T> or return T. With the second definition, that's not possible.
Bounded wildcards are subject to certain restrictions to avoid heap pollution.
When you use the wildcard ? extends X you know you can read generic information, but you cannot write.
For instance
List<String> jedis = new ArrayList<String>();
jedis.add("Obiwan");
List<? extends CharSequence> ls = jedis
CharSequence obiwan = ls.get(0); //Ok
ls.add(new StringBuffer("Anakin")); //Not Ok
The compiler avoided heap pollution when you tried to add a CharSequence (i.e. StringBuffer) to the collection. Because the compiler cannot be sure (due to wildcards) that the actual implementation of the collection is of type StringBuffer.
When you use ? super X you know you can write generic information, but you cannot be sure of the type of what you read.
For instance
List<Object> jedis = new ArrayList<Object>();
jedis.add("Obiwan");
List<? super String> ls = jedis;
ls.add("Anakin"); //Ok
String obiwan = ls.get(0); //Not Ok, we can´t be sure list is of Strings.
In this case, due to wildcards, the compiler knows that the actual implementation of the collection could be anything in the ancestors of String. Thus it cannot guarantee that what you will get will be a String. Right?
This same restrictions are the ones you would be subject too in any declaration with bounded wildcards. These are typically known as the get/put principle.
By using a type parameter T you change the story, from the method standpoint you are not using a bounded wildcard but an actual type and therefore you could "get" and "put" things into instances of the class and the compiler would not complain.
For instance, consider the code in Collections.sort method. If we write a method as follows, we would get a compile error:
public static void sort(List<? extends Number> numbers){
Object[] a = numbers.toArray();
Arrays.sort(a);
ListIterator<? extends Number> i = numbers.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((Number)a[j]); //Not Ok, you cannot be sure the list is of Number
}
}
But if you write it like this, you can do the work
public static <T extends Number> void sort(List<T> numbers){
Object[] a = numbers.toArray();
Arrays.sort(a);
ListIterator<T> i = numbers.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
And you could even invoke the method with collections bounded with wildcards thanks to a thing called capture conversion:
List<? extends Number> ints = new ArrayList<Integer>();
List<? extends Number> floats = new ArrayList<Float>();
sort(ints);
sort(floats);
This could not be achieved otherwise.
In summary, as others said from the caller standpoint they are alike, from the implementation standpoint, they are not.
No. On top of my head, I can think of the following differences:
The two versions are not override-equivalent. For instance,
class Foo {
public <T extends SomeBaseClass> void myMethod(Class<T> clz) { }
}
class Bar extends Foo {
public void myMethod(Class<? extends SomeBaseClass> clz) { }
}
does not compile:
Name clash: The method myMethod(Class) of type Bar has the same erasure as myMethod(Class) of type Foo but does not override it
If a type parameter appears more than once in a method signature, it always represents the same type, but if a wildcard appears more than once, each occurrence may refer to a different type. For instance,
<T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) > 0 ? a : b;
}
compiles, but
Comparable<?> max(Comparable<?> a, Comparable<?> b) {
return a.compareTo(b) > 0 ? a : b;
}
does not, because the latter may be called by
max(Integer.MAX_VALUE, "hello");
The method body may refer to the actual type used by the caller using a type parameter, but not using a wildcard type. For instance:
<T extends Comparable<T>> T max(T... ts) {
if (ts.length == 0) {
return null;
}
T max = ts[0];
for (int i = 1; i < ts.length; i++) {
if (max.compareTo(ts[i]) > 0) {
max = ts[i];
}
}
return max;
}
compiles.
#Mark #Joachim #Michael
see the example in JLS3 5.1.10 Capture Conversion
public static void reverse(List<?> list) { rev(list);}
private static <T> void rev(List<T> list){ ... }
so the <?> version can do anything the <T> version can do.
this is easy to accept if the runtime is reified. a List<?> object must be a List<X> object of some specific non-wildcard X anyway, and we can access this X at runtime. So there's no difference using a List<?> or a List<T>
With type erasure, we have no access to T or X, so there's no difference either. We can insert a T into a List<T> - but where can you get a T object, if T is private to the invocation, and erased? There are two possibilities:
the T object is already stored in the List<T>. so we are manipulating elements themselves. As the reverse/rev example shows, there's no problem doing this to List<?> either
it comes out-of-band. There's other arrangement made by the programmer, so that an object somewhere else is guaranteed to be of type T for the invocation. Unchecked casting must be done to override compiler. Again, no problem to do the same thing to List<?>