dombimihaly89
dombimihaly89

Reputation: 51

Why unmodifiableList in Collections parameter is <? extends T>

There is the unmodifiableList method in the Collections class. It returns a List<T> but in the parameters it accepts List<? extends T>.

So if I understand this right then this method accepts a List which has T objects or objects that inherited from T class. But I don't understand why the <? extends T> part in the parameter. I mean the parameter determines the return type of the method. If the method is called with List<Animal> then the return will be List<Animal> so it is going to be the same. Why we need this <? extends T>? Why don't we need just List<T> in the parameter list? I don't understand this.

If you could provide an example I would be happy about it. Thank you in advance!

Upvotes: 4

Views: 150

Answers (2)

rzwitserloot
rzwitserloot

Reputation: 103018

So if I understand this right then this method accepts a List which has T objects or objects that inherited from T class

This is oversimplifying matters.

a List<Number> can contain solely integers. The point of a List<Number> is that it is constrained to contain only number instances. Not that each instance MUST be Number and specifically Number - that would be impossible, as Number is abstract (no instances of Number itself can possibly exist, only instances of some subclass of it). The only difference between a List<Integer> containing only integers and a List<Number> containing only integers, is that you can add, say, a Double instance to that List<Number>, but you can't add it to a List<Integer>.

Because a method that takes, as argument, a List<Something> could invoke .add(), the type system needs to worry about the difference. It needs to do so even if this method does not, in fact, call add at all, and never intends to. The type system doesn't know that, and you're free to change the body of a method in some future version without that breaking backwards compatibility, thus, it matters. Even if you feel like it does not.

That then also explains your question:

If you have some method that demands a List<Number>, then you may provide a List<Integer> to Collections.unmodifiableList, and that's fine - Collections.uL will give you that List<Number>. This would ordinarily be broken, in that you can invoke .add(someDouble) which you should not be doing to a list of integers, but .add doesn't work on an unmodifiable, so it's fine.

Upvotes: 2

dan1st
dan1st

Reputation: 16373

List<? extends T> means it also accepts lists of subtypes.

Imagine having a class Plant and a class Tree that extends Plant.

You could create an unmodifiable List of Plants using a List<Tree> because Collections.unmodifiableList accepts lists of any subtype of T.

If it was List<T>, it would accept a List<Plant> as a parameter in order to create an unmodifiable List<Plant> but you could not create an unmodifiable List<Plant> using a List<Tree> as parameter.

Upvotes: 0

Related Questions