1

Here is an SSCCE:

import java.util.*;

class Test {
    public static void main(String[] args) {
        bar( foo() );
    }

    public static List<? extends CharSequence> foo() {
        return null;
    }

    public static void bar(List<CharSequence> baz) {
        // Nothing to see here
    }
}

This results in

bar(java.util.List<java.lang.CharSequence>) in Test cannot be applied to (java.util.List<capture#672 of ? extends java.lang.CharSequence>)
  1. Is there any possible way in which this example could fail? It is safe to cast <? extends CharSequence> to <CharSequence>, isn't it?
  2. How should I work around this (in a more complex setup) if not via casting?
just lerning
  • 876
  • 5
  • 20
  • It's not safe to cast. I think, it's good to explain through an example. Imagine: `foo()` creates and returns a `List`. Now, `bar()` tries to add a `CharSequence` to the list. Boom. If you want to make the `bar()` method more generic, you also have to define `List extends CharSequence>` as parameter (thus making it impossible to add anything except `null` to the list). – qqilihq Feb 15 '14 at 22:35
  • Because Generic types in Java aren't covariant. http://stackoverflow.com/questions/2660827/java-generics-covariance – Brian Roach Feb 15 '14 at 22:41

2 Answers2

3

Lets use standard example. You have classes

class Fruit{}
class Apple extends Fruit{}
class Banana extends Fruit{}

Now lets say you have reference for all kinds of Fruit lists like

List<? extends Fruit> list;

This reference will let you hold not only Fruit list but also Apple or Banana lists.

List<? extends Fruit> list = new ArrayList<Apple>();
//lets say we add some apples here to list

Do you think it would be safe to let List<Fruit> handle list of List<? extends Fruit> like

List<Fruit> fruits = list;

Think about it. Via List<Fruit> you can add all kinds of Fruits to list. It means you would be able to add Banana to currently hold list of Apples.

That is why Java will not let you use result of foo() which is List<? extends CharSequence> as argument for bar(List<CharSequence> baz).

Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • `2) How should I work around this` it depends on what is your goal. You can change `bar` to accept `List extends CharSequence>` but that will not allow you to add anything to list via this reference. – Pshemo Feb 15 '14 at 22:55
2

The problem is that when foo() returns the list, you don't know what the list has in it.

Let's say for example that foo() returns a list of StringBuilder. But now, bar() tries to add Strings to it. You broke the type-safety of this list.

If the list doesn't change in bar() I suggest changing bar to accept List<? extends CharSequence> and then you're good.

Avi
  • 21,182
  • 26
  • 82
  • 121
  • In other words: It would be fine the other way around (e.g., http://ideone.com/KNYkpv), but not *this* way around. This way around requires a potential downcast. – T.J. Crowder Feb 15 '14 at 22:39
  • @T.J.Crowder - Indeed. – Avi Feb 15 '14 at 22:40
  • So it is impossible to instantiate a class (`new Foo( xyz() );`) if `xyz()` returns ` extends Bar>`? Any way to get around this? – just lerning Feb 15 '14 at 22:45
  • If the constructor of `Foo` doesn't change the list than you're good. If you change the list, you might be needing to creating an inner copy of the list. – Avi Feb 15 '14 at 22:48