In Java Generics are invariant? - java

Compiling the below code is failing:
public static void swap(List<?> list, int i, int j) {
list.set(i, list.set(j, list.get(i)));
}
like:
Swap.java:5: set(int,capture#282 of ?) in List<capture#282 of ?> cannot be applied to (int,Object)
list.set(i, list.set(j, list.get(i)));
But if I do this:
public static void swap(List<?> list, int i, int j) {
swapHelper(list, i, j);
}
private static <E> void swapHelper(List<E> list, int i, int j) { list.set(i, list.set(j, list.get(i)));
}
Its working perfectly.
But I have a basic doubt here. Generics are said to be invariant, so List<String> is not subtype of List<Object>, right?
If that is the case, then how come in the above method, we are able to pass List<?> to List<E>? How does this works?

the answer is wildcards.
List<?> is not the same as List<Object>
while java assumes both are collections of Object, the former will match the type of any other List<T>, while the latter will not match the type of any List<T> besides List<Object>.
example:
public void doSomething(List<Object> list);
This function will accept only List<Object> as it's parameter. However this:
public void doSomething(List<?> list);
will accept any List<T> as it's parameter.
This can be extremely useful when used with generic constraints. For instance if you'd like to write a function that manipulates numbers (Integers, Floats, etc.) you could:
public void doSomethingToNumbers(List<? extends Number> numbers) { ... }

Because you are using wildcard capturing.
In some cases, the compiler infers the type of a wildcard. For
example, a list may be defined as List but, when evaluating an
expression, the compiler infers a particular type from the code. This
scenario is known as wildcard capture.
Thanks to the helper method, the compiler uses inference to determine T, the capture variable, in the invocation.

List<?> means "list of an unknown type". You can pass a List<String> for it, not because it is a subclass (it isn't), but because "unknown type" is supposed to accept whatever you throw at it.
Because type is unknown, you cannot perform operations with it, that require knowing the type of the elements (like set or add etc).
List<E> is a generic. It is not the same as List<?> even though it kinda looks similar.
One difference is, as you noted, you can do things like set or add to it, because the type of the element is now known.
Whildcards as function parameters are not very useful (<E> void foo(List<E> l) is not much different from void foo(List<?> l)). They also bypass all the compile-time type check, thus defeating the purpose of generics, and should really be avoided.
A more common (and less harmful) use for wildcards is in the return types: List<? extends DataIterface> getData() means that getData returns a list of some objects that implement a DataInterface, but won't tell you their concrete type. This is often done in the API design to isolate implementation details from the interface. The convention usually is, that you can pass a list of objects, returned by the API to other API methods, and they will accept and handle them. This concept is called existential types.
Also, note that getData from the above example can return lists of different types, depending on some condition, that is outside of the caller's domain, unlike if it was declared to return List<E>, in which case, the caller would have to specify the expected type in some way.

Related

any use case of declaring a List<?> [duplicate]

I am refreshing my knowledge on Java generics. So I turned to the excellent tutorial from Oracle ... and started to put together a presentation for my coworkers. I came across the section on wildcards in the tutorial that says:
Consider the following method, printList:
public static void printList(List<Object> list) {
...
The goal of printList is to print a list of any type, but it fails to achieve that goal — it prints only a list of Object instances; it cannot print List<Integer>, List<String>, List<Double>, and so on, because they are not subtypes of List<Object>. To write a generic printList method, use List<?>:
public static void printList(List<?> list) {
I understand that List<Object> will not work; but I changed the code to
static <E> void printObjects(List<E> list) {
for (E e : list) {
System.out.println(e.toString());
}
}
...
List<Object> objects = Arrays.<Object>asList("1", "two");
printObjects(objects);
List<Integer> integers = Arrays.asList(3, 4);
printObjects(integers);
And guess what; using List<E> I can print different types of Lists without any problem.
Long story short: at least the tutorial indicates that one needs the wildcard to solve this problem; but as shown, it can be solved this way too. So, what am I missing?!
(side note: tested with Java7; so maybe this was a problem with Java5, Java6; but on the other hand, Oracle seems to do a good job regarding updates of their tutorials)
Your approach of using a generic method is strictly more powerful than a version with wildcards, so yes, your approach is possible, too. However, the tutorial does not state that using a wildcard is the only possible solution, so the tutorial is also correct.
What you gain with the wildcard in comparison to the generic method: You have to write less and the interface is "cleaner" since a non generic method is easier to grasp.
Why the generic method is more powerful than the wildcard method: You give the parameter a name which you can reference. For example, consider a method that removes the first element of a list and adds it to the back of the list. With generic parameters, we can do the following:
static <T> boolean rotateOneElement(List<T> l){
return l.add(l.remove(0));
}
with a wildcard, this is not possible since l.remove(0) would return capture-1-of-?, but l.add would require capture-2-of-?. I.e., the compiler is not able to deduce that the result of remove is the same type that add expects. This is contrary to the first example where the compiler can deduce that both is the same type T. This code would not compile:
static boolean rotateOneElement(List<?> l){
return l.add(l.remove(0)); //ERROR!
}
So, what can you do if you want to have a rotateOneElement method with a wildcard, since it is easier to use than the generic solution? The answer is simple: Let the wildcard method call the generic one, then it works:
// Private implementation
private static <T> boolean rotateOneElementImpl(List<T> l){
return l.add(l.remove(0));
}
//Public interface
static void rotateOneElement(List<?> l){
rotateOneElementImpl(l);
}
The standard library uses this trick in a number of places. One of them is, IIRC, Collections.java
Technically, there is no difference between
<E> void printObjects(List<E> list) {
and
void printList(List<?> list) {
When you are declaring a type parameter, and using it only once, it essentially becomes a wildcard parameter.
On the other hand, if you use it more than once, the difference becomes significant. e.g.
<E> void printObjectsExceptOne(List<E> list, E object) {
is completely different than
void printObjects(List<?> list, Object object) {
You might see that first case enforces both types to be same. While there is no restriction in second case.
As a result, if you are going to use a type parameter only once, it does not even make sense to name it. That is why java architects invented so called wildcard arguments (most probably).
Wildcard parameters avoid unnecessary code bloat and make code more readable. If you need two, you have to fall back to regular syntax for type parameters.
Hope this helps.
Both solutions are effectively the same, it's just that in the second one you are naming the wildcard. This can come handy when you want to use the wildcard several times in the signature, but want to make sure that both refer to the same type:
static <E> void printObjects(List<E> list, PrintFormat<E> format) {

unable to understand wildcard generics in this example in Java?

while reading through this article I got stuck here. I am pasting this from the link. I do not understand the reasoning given for why List<Number> or List<? extends Number> cannot be used here.
public void doStuff( List<Integer> list ) {
list.add(1);
// do stuff
list.get(0);
}
We can generalize this one step further by generalizing the generic parameter:
public void doStuff( List<? super Integer> list ) {
list.add(1);
// do stuff
list.get(0);
}
Some readers might ask why the more intuitively List<Number> can’t be used here. Indeed, we
could try to define the method as taking a List<Number> or a List<? extends Number>, but the first
definition would exclude the possibility for passing in an actual ArrayList<Integer>, while the
second definition would disallow the add() method (as someone may otherwise be passing an
ArrayList<Float> in, and would find an Integer to be between the Floats after the call to doStuff).
In normal Java, yes, an Integer is a Number. But in generics, List<Integer> is not a List<Number>.
To see why, attempt to assign a List<Integer> to a List<Number> and see what happens:
List<Number> numberList = new ArrayList<Integer>(); // not allowed
// This would have been allowed, even though the argument is
// boxed to a `Double`, not a `Integer`.
numberList.add(8.6);
But what about <? extends Number>? Wouldn't that cover a List<Integer>? Yes, but the references loses information about the exact type of Number. What if that was the case?
List<? extends Number> numberList = new ArrayList<Integer>(); // allowed
numberList.add(8.6); // disallowed
The reason is that the List<? extends Number> could be of anything that extends Number, such as List<BigDecimal>. So it must disallow calling the add method (or any method in that class with the generic type parameter as a parameter to that method) (except for null) to maintain type safety.
Java is perhaps a bit confusing because there is a bit of a double standard at work.
First you must consider that both arrays and collections are reference types, i.e. their instances are objects whose data is allocated to heap memory and indicated by a reference pointer.
Both arrays and collections therefore have two types at work: the type of object itself as well as the types of each of the components in the array or collection. To make this concrete, here is an example:
String[] strings = new String[] { "AA", "BB", "CC" };
The type of the object that is created is String[] and the types of all the components is String.
Arrays are covariant which allows the JVM to cast both the object type and the component type together. This is why assignments like this are valid:
Object[] objects = strings;
For arrays, because Object is a supertype of String, then Object[] is also a supertype of String[]. Arrays are covariant.
This does NOT apply to reference types that are not arrays, eg. Collections. Collections are invariant. Therefore, even though a Integer is a subtype of Number, collections are invariant and so List<Integer> is NOT a subtype of List<Number>.
For the first case, accepting a List<Number> only allows a List (ArrayList, LinkedList, ...) of Number elements, not a List of any other type (including Integer). The list has to be specifically typed in the calling function as List<Number> (or ArrayList<Number>, or LinkedList<Number>, or ...). In other words, the type of list is flexible but the generic argument is not.
In the second case, use the "is a" wording and it makes sense. An Integer "is a" Number, but the reverse is not always true. Since the code in the example is assuming all values in use within the function are integers, it must put a limit on the generic that prevents anything less specific than Integer from being passed in.
We need to examinate two things:
What does the wildcard mean in the signature void doStuff(Foo<? super Bar> foo)
What does the wildcard mean inside the method body
Java has only one very simple rule to decide the subtype relation between Foo<A> and Foo<B>: none is a subtype of the other. We say that generic types are invariant, and even if there's a rationale because the Java designers made it this way, from your point of view it's an arbitrary decision.
It's the angle brackets that confuse us, poor developers: we have no problem in accepting that FooBar and FooQoo are not related in any way; but for some reason we need to believe that Foo<Qoo> and Foo<Bar> are. No, that's not the case.
No matter how A and B relate to each other, X<A> and X<B> are not
related.
No matter how A and B relate to each other, X<A> and X<B>
are not related.
No matter how A and B relate to each other, X<A>
and X<B> are not related.
Once you are convinced of the above, please observe this snippet:
List<Double> doubles = ...;
List<Integer> integers = ...;
Number firstDouble = doubles.get(0);
Number firstInteger = integers.get(0);
Calling get(0) on both lists gives us a Number-compatible object. We may want to put the call to get() in a method like getFirstOfList(list) but we just learned that such a method can't exist, because it would accept two totally unrelated types.
This is where wildcards come into play! We observe that calling get() on a List<Number>, a List<Integer>, a List<Double> (and so on) return a Number-compatible object (ie Number or a subtype of it), so there must be a way to express this at the language level. The Java designers gave us the wildcard, which works like this: when you declare
public void doStuff(List<? extends Number> arg);
it has the same effect as declaring the following infinite list:
public void doStuff(List<Number> arg);
public void doStuff(List<Integer> arg);
public void doStuff(List<Double> arg);
public void doStuff(List<Float> arg);
public void doStuff(List<BigDecimal> arg);
...
Without the device of the wildcard you'd have to write one method for each supported list type (which btw is illegal in Java, but that's another story).
The wildcard I used in my example has an upper bound, identified by the extends keyword. The snippet you pasted, instead, adopts a lower bounded wildcard in the method signature (super). Actually it may contain some errors because for example:
you can't pass a List<Integer> to doStuff()
you can only get an Object from list.get(index)
so I will just tell you that the signature
void doStuff(List<? super Number> arg);
stands for the finite list:
void doStuff(List<Number> arg);
void doStuff(List<Object> arg);
and you can put any Number you like in a List<? super Number> but you'll only get() Object's from it.

List vs List<Object>

Why do we lose type safety when using List and not while using List<Object>? Aren't they basically the same thing?
EDIT: I found that the following gives a compilation error
public class TestClass
{
static void func(List<Object> o, Object s){
o.add(s);
}
public static void main(String[] args){
func(new ArrayList<String>(), new Integer(1));
}
}
whereas this doesn't
public class TestClass
{
static void func(List o, Object s){
o.add(s);
}
public static void main(String[] args){
func(new ArrayList<String>(), new Integer(1));
}
}
Why?
List is a list of some type you don't know. It could be a List<String>, List<Integer>, etc.
It's effectively equivalent to List<?>, or List<? extends Object>, except that it doesn't document that fact. It's only supported for backwards compatibility.
List<Object> is a list of Objects. Any object of any type can be put inside it, contrary to a List<String>, for example, which only accepts strings.
So no, they're not the same thing.
Why do we lose type safety when using List and not while using List<Object>? Aren't they basically the same thing?
No they are not the same thing.
If you are providing an API,
class API {
static List<Object> getList() { ... }
static void modifyList(List<Object> l) { ... }
}
and a client uses it improperly
List<Integer> list = API.getList();
API.modifyList(list);
for (Integer i : list) { ... } // Invalid
then when your API specifies List<Object> they get a compile-time error, but they don't when API.getList() returns a List and API.modifyList(list) takes a List without generic type parameters.
EDIT:
In comments you mentioned changing
void func(List<Object> s, Object c) { s.add(c); }
to
void func(List s, Object c) { s.add(c); }
so that
func(new List<String>(), "");
would work.
That is violating type safety. The type-safe way to do this is
<T> void func(List<? super T> s, T c) { s.add(c); }
which is basically saying that func is a parameterized function that takes a List whose type can be any super class of T, and a value of type T, and adds the value to the list.
A List<Object> isn't really any more typesafe than a List. However, the Object in the code does imply intent. When someone else looks at it later, they can see that you purposefully chose Object as the type, rather than wondering if you just forgot to put a type or are storing something else and typecasting it elsewhere.
Since code gets read more than it gets written, hints at the intent of the code can be very valuable later on.
The reason you have a compiler warning when you use List instead of List<Object> is that when you have a List the compiler doesn't know what type of List it is, so while you could treat it as a List<Object>, the compiler can't ensure that at some other point in the code it wasn't set to reference a List<String> and the type safety of the Generics cannot be checked. That is really the compiler warning here - it is saying it can't help ensure the type safety of the generics, and it won't happen at runtime either (until at some later point there is an actual cast in the code).
For purposes here, you could say they're the same thing. But presumably you almost never actually fill a List with pure instance of Object. They're Strings or something. In this example, List<Object> is technically using generics but not really taking any advantage of it. So, it loses the compile-time type checking of generics.
Type Erasure is one answer and the backward compatibility to pre Java 1.5 and tighter type check in case of first one.
Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety.
Generate bridge methods to preserve polymorphism in extended generic types.
Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.

Java : What is - public static<T> foo() {...}?

I saw a java function that looked something like this-
public static<T> foo() {...}
I know what generics are but can someone explain the in this context? Who decides what T is equal to? Whats going on here?
EDIT: Can someone please show me an example of a function like this.
You've missed the return type out, but apart from that it's a generic method. As with generic types, T stands in for any reference type (within bounds if given).
For methods, generic parameters are typically inferred by the compiler. In certain situations you might want to specify the generic arguments yourself, using a slightly peculiar syntax:
List<String> strings = Collections.<String>emptyList();
In this case, the compiler could have inferred the type, but it's not always obvious whether the compiler can or can't. Note, the <> is after the dot. For syntactical reasons the type name or target object must always be specified.
It's possible to have generic constructors, but I've never seen one in the wild and the syntax gets worse.
I believe C++ and C# syntaxes place the generic types after the method/function name.
The context is a generic method as opposed to a class. The variable <T> applies only to the call of the method.. The Collections class has a number of these; the class itself is not generic, but many of the methods are.
The compiler decides what T is equal to -- it equals whatever gets the types to work. Sometimes this is easier then others.
For example, the method static <T> Set<T> Collections.singleton(T o) the type is defined in the parameter:
Collections.singleton(String T)
will return a Set<String>.
Sometimes the type is hard to define. For example sometimes there is not easily enough information to type Collection.emptyList(). In that case you can specify the type directly: Collection.<String>emptyList().
T it's the formal type parameter wich will be replaced by the actual type
argument used at the instantiation of the object.
For example, here is the List and Iterator definitios in package java.util:
public interface List<E>{
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E>{
E next();
boolean hasNext();
}
Then you can instantiate a List this way:
List<String> ls = new ArrayList<String>()
Where you might imagine that List stands for a version of List where E has
been uniformly replaced by String:
public interface StringList{
void add(String x)
Iterator<String> iterator();
}

How do I use arrays of generic types correctly?

I have a class that maps incoming messages to matching readers based on the message's class. All message types implement the interface message. A reader registers at the mapper class, stating which message types it will be able to handle. This information needs to be stored in the message reader in some way and my approach was to set a private final array from the constructor.
Now, it seems I have some misunderstanding about generics and / or arrays, that I can't seem to figure out, see the code below. What is it?
public class HttpGetMessageReader implements IMessageReader {
// gives a warning because the type parameter is missing
// also, I actually want to be more restrictive than that
//
// private final Class[] _rgAccepted;
// works here, but see below
private final Class<? extends IMessage>[] _rgAccepted;
public HttpGetMessageReader()
{
// works here, but see above
// this._rgAccepted = new Class[1];
// gives the error "Can't create a generic array of Class<? extends IMessage>"
this._rgAccepted = new Class<? extends IMessage>[1];
this._rgAccepted[0] = HttpGetMessage.class;
}
}
ETA:
As cletus correctly pointed out, the most basic googling shows that Java does not permit generic arrays. I definitely understand this for the examples given (like E[] arr = new E[8], where E is a type parameter of the surrounding class). But why is new Class[n] allowed? And what then is the "proper" (or at least, common) way to do this?
Java does not permit generic arrays. More information in the Java Generics FAQ.
To answer your question, just use a List (probably ArrayList) instead of an array.
Some more explanation can be found in Java theory and practice: Generics gotchas:
Generics are not covariant
While you might find it helpful to
think of collections as being an
abstraction of arrays, they have some
special properties that collections do
not. Arrays in the Java language are
covariant -- which means that if
Integer extends Number (which it
does), then not only is an Integer
also a Number, but an Integer[] is
also a Number[], and you are free to
pass or assign an Integer[] where a
Number[] is called for. (More
formally, if Number is a supertype
of Integer, then Number[] is a
supertype of Integer[].) You might
think the same is true of generic
types as well -- that List<Number>
is a supertype of List<Integer>, and
that you can pass a List<Integer>
where a List<Number> is expected.
Unfortunately, it doesn't work that
way.
It turns out there's a good reason it
doesn't work that way: It would break
the type safety generics were supposed
to provide. Imagine you could assign a
List<Integer> to a List<Number>.
Then the following code would allow
you to put something that wasn't an
Integer into a List<Integer>:
List<Integer> li = new ArrayList<Integer>();
List<Number> ln = li; // illegal
ln.add(new Float(3.1415));
Because ln is a List<Number>, adding
a Float to it seems perfectly legal.
But if ln were aliased with li, then
it would break the type-safety promise
implicit in the definition of li --
that it is a list of integers, which
is why generic types cannot be
covariant.
It is right what cletus said. There is a general mismatch between the usually enforced invariance of generic type parameters vs. covariance of Java arrays.
(Some background: Variance specifies how types relate to each other concerning subtyping. I.e. because of generic type parameters being invariant
Collection <: Collection does not hold. So, concerning the Java type system, a String collection is no CharSequence collection. Arrays being covariant means that for any types T and U with T<:U, T[] <: U[]. So, you can save a variable of type T[] into a variable of type U[]. Since there is a natural need for other forms of variance, Java at least allows wildcards for these purposes.)
The solution (the hack, actually) I often use, is declaring a helper method which generates the array:
public static <T> T[] array(T...els){
return els;
}
void test(){
// warning here: Type safety : A generic array of Class is created for a varargs parameter
Class<? extends CharSequence>[] classes = array(String.class,CharSequence.class);
}
Because of erasure the generated arrays will always be of type Object[].
And what then is the "proper" (or at least, common) way to do this?
#SuppressWarnings(value="unchecked")
public <T> T[] of(Class<T> componentType, int size) {
return (T[]) Array.newInstance(componentType, size);
}
public demo() {
Integer[] a = of(Integer.class, 10);
System.out.println(Arrays.toString(a));
}
Arrays are always of a specific type, unlike how Collections used to be before Generics.
Instead of
Class<? extends IMessage>[] _rgAccepted;
You should simply write
IMessage[] _rgAccepted;
Generics don't enter into it.
IMHO,
this._rgAccepted = (Class<? extends IMessage>[])new Class[1];
is the appropriate way to handle this. Array component types have to be reified types, and Class is the closest reified type to Class<whatever>. It'll work just as you would expect a Class<whatever>[] to work.
Yes, technically it is unchecked and might cause issues later if you cast it to another more general array type and put wrong stuff in it, but since this is a private field in your class, I presume you can make sure it is used appropriately.

Categories

Resources