<? extends > Java syntax - java

This code:
List<? extends Reader> weirdList;
weirdList.add(new BufferedReader(null));
has a compile error of
The method add(capture#1-of ? extends Reader) in the type
List is not applicable for the
arguments (BufferedReader)
Why? BufferedReader extends reader, so why isn't that a "match"?

List<? extends Reader> weirdList can hold reference to any type of List that stores any type of Reader. So it is possible that
List<? extends Reader> weirdList1 = new ArrayList<BufferedReader>();
List<? extends Reader> weirdList2 = new ArrayList<FileReader>();
If Java would allow you to add BufferedReader to weirdList1 it would also have to let you add BufferedReader to weirdList2 (reference type is the same) which is not suppose to happen since weirdList2 should store only FileReaders.

When the compiler sees <? extends Reader>, then it assumes that it could be any type that is or extends Reader. It could be something that is imcompatible with BufferedReader, such as StringReader. So if the generic type in the class definition shows up in the parameter of a method such as add, and the type of the instance has something like <? extends Something>, the compiler must disallow it for type safety reasons. In this example, it could be List<StringReader>, so you shouldn't be able to add a BufferedReader here.

For the variable you gave:
List<? extends Reader> weirdList;
All of the following assignments are valid:
weirdList = new ArrayList<Reader>();
weirdList = new ArrayList<FileReader>();
weirdList = new ArrayList<BufferedReader>();
weirdList = new ArrayList<InputStreamReader>();
Hopefully this explains your compile error. What you're trying makes sense if weirdList holds a value of type ArrayList<BufferedReader>, but doesn't make sense for a value of type ArrayList<FileReader>. Since a variable of type List<? extends Reader> can hold a value of either type (and more!), Java calls that an error.
Generics in Java are hard to get your head around. You can think of the List<? extends Reader> type as being mostly useful for assignment or parameter types in methods so that they can accept a wide variety of types. For "regular use", you're probably better off with a "bare" generic like List<Reader> or even List<BufferedReader>.

Related

Why does this compile? Java

I was taught that the following compiles:
Collection <? extends T> collection;
List<T> list;
collection = list; // Compiles
With the reason that "that's how Java developers defined it". I would like to know the rationale behind it. It compiles but can make problems during runtime (e.g. we wouldn't be able to add any objects to collection).
Any clarification would be appreciated.
Edit: I am referring to the fact that an Object of generic type ? extends T is pointing to an Object of generic type T. It seems rather counterintuitive.
Edit: I am referring to the fact that an Object of generic type ? extends T is pointing to an Object of generic type T. It seems rather counterintuitive.
To understand this, you have to understand what exactly a Collection<? extends T> is.
It is: a Collection with elements of a specific, but unknown type (indicated by the ?) that extends T.
Note that it is not a Collection of objects of arbitrary (and possibly different) types that extend T (this is a misconception that many developers have about generic wildcards).
It's perfectly OK that you can assign a List<T> to a variable of type Collection<? extends T>, because List is a subtype of Collection, and the elements of a List<T> are indeed of the type ? extends T. (In this particular case, the actual type is the type T itself, but that still matches "some unknown type ? that extends T").
Note that using the wildcard actually throws away information about the exact type of the elements of the collection - it makes Java forget the exact type, and only makes it remember that it's an unknown type that extends T.
You cannot add anything to a collection of a wildcard parameterized type such as a Collection<? extends T>, precisely because the information about the exact type of the elements is missing. If you would try to add an element to such a collection, there's no way for the compiler to check if the type of the element you're adding is the right type.
If you try to call add() on a Collection<? extends T> you will get a compile error that says that the type of the object you're adding is not of the type "capture of ... of ? extends T". That basically means: "I cannot check that the object you're trying to add is of the unknown type ? extends T".
The type can also not be checked at runtime because of type erasure: type arguments are a compile-time only thing in Java, at runtime they don't exist anymore so also then there's not enough information to check that the element you're adding is of the right type.
It is because Collection is an interface. List is also an interface which extends Collection interface.
By Object oriented principles, parent class reference can hold the child class reference!
For e.g. If I have below
class Parent {
//Some code
}
class Child extends Parent {
//Some code
}
I can do this
Parent parentObject = new Child();
parentObject.childMethod(); or parentObject.parentMethod();
https://docs.oracle.com/javase/8/docs/api/java/util/List.html This docs can help !

Defenition of type parameter

I dont understand a strong defenition of type parameter in generic class or method. It's a reference type such that... what? Does it just non reifiable type? Is it true that all reference type for compiler is reifiable or not reifiable?
2.Consider the well known code:
List<? extends String> strs= new ArrayList<String>();
? extends String str;//error
strs.add("sd");//error
Why ? extends String str; does not valid? I thinked that if we declare a reference to a generic type, for example List<E> strs; for some type E then compiler define type parameter to a specific type E.
I dont understand what occur in the case List<? extends String> strs? Does List<? extends String> and , for example List<String> parsing similarly at compile time or List<? extends String> parsing different from List<E> for some reifiable type E?
Generics are used to specify a type.
Consider the following class def:
public interface List<E> extends Collection<E>
This tells us there we have a List that can hold elements of any type.
Notice how there are no restrictions on E.
If we define a class like so:
public class MyList<T extends String> implements List<T>
We now have a MyList that implements List, but only accepts Strings (or decedents).
Inside this class we can refer to T.
public class MyList<T extends String> implements List<T> {
private ArrayList<T> internalStorage;
Key point
In the class definition we have defined what T is; it's any class based on String.
Inside the class T can thus be referenced.
However the flavor of T does not get fixed until the class actually gets instantiated:
MyList<MyStringType> test = new MyList<MyStringType>(parameters); //java 6
MyList<MyStringType> test = new MyList<>(parameters); //java 7, same but shorter.
Now Java knows what T means inside the MyList class T is a MyStringType.
Armed with is knowledge Java compiles the class and replaces all references to T with references to the actual class MyStringType.
It completely forgets about T.
Now inside the class note that everywhere T is mentioned it will get replaced by MyStringType.
But what if I want to handle a string, but not necessarily the MyStringType.
Solution:
I define a member like so:
List<? extends String> strs; //Will fill the data in later
Now we have a List called strs that will only accept strings, but that will not be forced to use strings of type MyStringType.
This list is not bound to the definition of T that was fixed when MyList was instantiated.
When we assign a value to the strs, the flavor of the List if fixed. In your example it will be a List of String.
? extends String str;//error
The variable cannot be fixed, because its type cannot be nailed down when the class that holds it gets created.
Generics is designed for read and not for write. This is why you can use generics in parameters for a method, but cannot use it for declare a variable that you can use after for read/write from it :-)

Wildcard java extends

Consider the following code:
List<? extends Integer> lst= new ArraList<Integer>();
lst.add(5);//Compile error
lst.get(5);//OK
In the second string we have compile error, because we must guaranted have method add(int) in all potencial subtypes of List<? extends Integer> and compiler know that its null only, third string returns unknow type and compiler cast him to Object, isnt it?
PECS. Producer extends, Consumer super.
List<? super Integer> lst= new ArrayList<Integer>();
lst.add(5);// No Compile error
The list is a consumer now, you put objects into it...
Also this
lst.get(5);
Is a different cake... You provide the Integer index of which you want to get... (Not to mention what Sotirios mentioned: the return type will be Object in this case. Also, in this role, the list is a provider...)
Once you have a List<? extends Integer>, the compiler doesn't know whether it's Integer or a subtype. The compiler can't ensure the type safety of adding anything except null (really, passing anything to a method taking a generic type parameter, including the add method), so it disallows it. This occurs despite the fact that Integer is final and no subclasses are allowed.
For the get method, the compiler knows that the return type is some kind of Integer, so it allows the call and places an implicit cast to Integer.
You cannot add anything except null to a List bounded by a wildcard because you never know the underlying type.
List<? extends Integer> lst= new ArrayList<Integer>();
lst.add(5); // Compile error
lst.get(5); // 5 is just the index
You can however get an element because you know it must be an Integer (in this case).
It's hard to explain with Integer because it's a class that cannot be extended. But take this
public class Foo {}
public class Bar extends Foo {}
public class Zoop extends Foo {}
What could you add to
List<? extends Foo> fooList = new ArrayList<Zoop>(); // could come from a method
?
The list is declared as ? extends Foo even though the runtime object's generic type is Zoop. The compiler therefore cannot let you add anything. But you are guaranteed to be operating on Foo objects, so you can retrieve them fine.

Can the Object class really be a lower bound?

Why is the following legal when String & Integer are not super classes of Object ?
List<? super Object> mylist = new ArrayList<Object>();
mylist.add("Java"); // no compile error
mylist.add(2);
I'm aware that wild card guidelines use lower bounded wild cards and super for 'out' variables but it seems that Object doesn't function as a 'lower bound' in this case.
Also is this the only way to allow addition of any type into a list ?
It's really simple. Remember that in Java, an instance of a subtype is also an instance of its supertypes.
Look at the signature of add
public boolean add(E e)
That means whatever you pass something whose type is E or any subtype of E.
You have a List<? super Object>. So you can pass to myList.add() anything whose type is ? super Object (an unknown type which could be Object or supertype thereof) or any subtype thereof.
Is Integer a subtype of all types contained by ? super Object? Of course. Integer is a subtype of Object, which is a subtype of all types contained by ? super Object (of course, in this case, only Object satisfies this).
You're confusing the type parameter with the things you can pass to methods. The type argument of List<? super Object> is an unknown type that is a supertype of Object, so Integer or String cannot be the actual type parameter. In fact, in this case the only valid actual type argument would be Object. But what you're asking when you pass something to the method is, is the thing I'm passing a subtype? And the answer is yes.
I agree that it's confusing, but here's what's happening.
In this line of code:
List<? super Object> mylist...
You're saying that myList is a List, where each element can be of a type that is Object or a superclass of Object. However, you're only declaring the type of myList here.
What the wildcard does is restricts your implementation of myList.
Then, you do this:
List<? super Object> mylist = new ArrayList<Object>();
Now what you're doing is instantiating an ArrayList<Object>. Your lower bound wildcard is used to check that this is valid. It is valid, because Object matches ? super Object. At this point, you have a List<Object> and your ensuing method calls are permitted.
It's because Object is a superclass for Integer and String. You're interpreting the generic relationship the other way around.
Edit
Think about this situation:
List<? extends myClass> listOfMyClass = new ArrayList<Object>();
In this case, you'll end up with a list of Object type elements but that have to respect the restriction added by the declaration of the listOfMyClass list.
You'll be able to add any object that belongs to the myClass hierarchy to the list. The ArrayList that's implementing the List interface will hold (and return) Object type elements when requested.
Of course, you can define this:
List<? extends myClass> listOfMyClass = new ArrayList<mySuperClass>();
As you might now, the ArrayList must contain objects with the same type or a supertype of myClass and, in this case, that's the mySuperClass. This list will return mySuperClass objects qhen requested.
Taking ClassX as a class that does not belong to the mySuperClass hierarchy, the following line won't compile:
List<? extends myClass> listOfMyClass = new ArrayList<ClassX>();
That's because ClassX is not a superclass of myClass.

What is the difference between A<T extends B> and A<? extends B>?

I am a new java learner. Recently I was reading Generic programming and got my self confused with this...
A<T extends B> and A<? extends B>
First of all, those are completely different constructs used in different contexts.
A<T extends B> is a part of generic type declaration such as
public class A<T extends B> { ... }
It declares generic type A with type parameter T, and introduces a bound on T, so that T must be a subtype of B.
A<? extends B> is a parameterized type with wildcard, it can be used in variable and method declarations, etc, as a normal type:
A<? extends B> a = ...;
public void foo(A<? extends B> a) { ... }
Variable declaration such as A<? extends B> a means that type of a is A parameterized with some subtype of B.
For example, given this declaration
List<? extends Number> l;
you can:
Assign a List of some subtype of Number to l:
l = new ArrayList<Integer>();
Get an object of type Number from that list:
Number n = l.get(0);
However, you can't put anything into list l since you don't know actual type parameter of the list:
Double d = ...;
l.add(d); // Won't compile
? is what is called a wildcard. It means anything that extends B.
When you write List<T extends String>, your List can contains only elements of type T.
When you write List<? extends String>, your List can contains any element that extends String
I hope I'm clear, since these concepts are complicated.
(a long comment, not an answer)
Totally different things. The similarity in syntax is a grave mistake made by Java. And this mistake leads to a bigger mistake - many people try to understand wildcard as a type parameter (i.e. wildcard capture)
There was no such thing as A<? extends B> until Java invented it. Until then the syntax used by researchers was A<B+>. Java thought that it is too mysterious for our poor programmers, so it invented that syntax A<? extends B> that seems to read better on first round.
Well it is damn verbose and ugly. If an API has a few wildcard, it looks like vomit of symbols.
But the worse thing is the confusion it causes. It looks like a type parameter. And Java did that on purpose! Java did not believe that its programmers can ever understand covariant types, so syntactically it made the convariant types look like parameterized types, to guide programmers into the erroneous way of understanding, that, admittedly, can be useful in occasions, but ultimately makes people clueless.
Generics is a complicated subject in general, and especially in Java. But basically the difference is:
T extends B
There is a specific type T, it is just limited to being B or a subclass of B, but it is a specific know type. Any plain old generic declaration is like saying: <T extends Object> By saying T extends B, we are saying that T is more limited than any object, it has to specifically be a type of B.
? extends B
This means that the generic type is unknown, exactly, but what we can say about it is that it extends B. It may be B, it may be a subclass of B. With a wildcard and the word extends, it means that you can get B out of the object, but you cannot put anything in the object in a type safe way. (? super B means the opposite - you can put something in a method parameter that is a B or a superclass of B, but you cannot be sure what the return value of a method would be.)

Categories