开发者

Why does ListDataModel not work with a bounded type parameter?

开发者 https://www.devze.com 2023-03-31 19:04 出处:网络
I just tried to create a ListDataModel with a bounded type, li开发者_C百科ke this: DataModel<? extends Foo> model = new ListDataModel<? extends Foo>(fooList);

I just tried to create a ListDataModel with a bounded type, li开发者_C百科ke this:

DataModel<? extends Foo> model = new ListDataModel<? extends Foo>(fooList);

, where fooList is of the type List<? extends Foo>. I get the following error:

unexpected type
  required: class or interface without bounds
  found: ? extends Foo

My current workaround is to copy my data into an ArrayList<Foo>, and build a DataModel<Foo> from that, but I would like to know why this is necessary, and if there is any way to make it work?


<? extends Foo> means "some type, I don't know which one, which is or extends Foo". When constructing the data model, you need to tell him which type of data it contains, not just one unknown type.

Just construct your data model like this:

DataModel<? extends Foo> model = new ListDataModel<Foo>(fooList);

Unfortunately, the ListDataModel<Foo> constructor only accepts a List<Foo>, and not a List<? extends Foo>. It seems to me like a misconception. For example the HashSet<E> constructor takes a Collection<? extends E> as argument. If you accept the type safety warning, just casting your list to a List<Foo> should work.


Since ListDataModel is read only, it is wrong for its constructor to accept only List<E>. It's ok to cast to bypass this design flaw.

A more general question: suppose ListDataModel is writable, what now?

If fooList is a List<? extends Foo>, then it certainly is a List<W> for a concrete W which extends Foo. Then we should be able to new ListDataModel<W>(fooList), the result type is a DataModel<W>, which is assignable to DataModel<? extends Foo> model.

This is how compiler internally reason about wildcards (wildcard capture); too bad we can't access W directly in Java (it's a so called non-denotable type), but we can cause wildcard capture through method invocation:

static <W> ListDataModel<W> make(List<W> list)
{
    return new ListDataModel<W>(list);
}

List<? extends Foo> fooList = ...;
DataModel<? extends Foo> model = make( fooList );

When compiling make( fooList ), compiler internally refines the type of fooList to a List<W> where <W extends Foo>; then the rest works natually.

In Java 7, type inference is extended to constructors with <> syntax

List<? extends Foo> fooList = ...;
DataModel<? extends Foo> model = new ListDataModel<>(fooList); // OK in Java 7

With <>, constructor call is pretty much the same as method calls; so make() is no longer needed. Prior to Java 7, static factory methods like make() were needed to amend the problem that constructors don't do inference. That practice is now obsolete.

0

精彩评论

暂无评论...
验证码 换一张
取 消