简体   繁体   中英

Java generic type inheritance, List element type inference

I have the following single-level inheritance. One thing that I can't wrap my head around is the fact that, getLine() is inferred as BaseLine without cast because of BaseDocument<T extends BaseLine> . But for list this doesn't apply, each element is returned as Object . My questions are:

  1. Why compiler can't infer the element type as BaseLine .

  2. How to change the implementation so I can get elements as BaseLine while iterating.

     public void test(){ BaseDocument baseDocument = new Document(); for (Object orderLine: baseDocument.getOrderLines()) { } BaseLine line = baseDocument.getLine(); } static class Document extends BaseDocument<Line> { @Override public List<Line> getOrderLines() { return null; } @Override public Line getLine() { return null; } } static abstract class BaseDocument<T extends BaseLine> { public abstract List<T> getOrderLines(); public abstract T getLine(); } static class Line extends BaseLine { } static abstract class BaseLine { }

When you have:

BaseDocument baseDocument = new Document();

You're using a raw type . A raw type erases all the generic information from the class. That includes other generic types. So with the above it's as if the class was written like so:

static abstract class BaseDocument {

  public abstract List getOrderLines();

  public abstract BaseLine getLine();
}

The type parameter of List is implicitly bounded by Object and so erases to Object .

You should never use raw types unless you're forced to by legacy code (written before Java 5). If you don't want to give an actual type then use a wildcard:

BaseDocument<?> baseDocument = new Document();
for (BaseLine orderLine : baseDocument.getOrderLines()) {
  // do something...
}

And you can leave the implementation of BaseDocument as is.

EDIT: This answer is more on the unsafe side, in my opinion. Check the answer from @Slaw for a better explanation. It has flaws too as explained by the author. Beware of complications when choosing between answers

The reason is in this specific line BaseDocument baseDocument = new Document(); BaseDocumet<T extends BaseLine> is the generic type and requires its type declared otherwise it can't infer the type of T so it automatically resolves to Object .

One way to resolve the problem is to cast baseDocument.getOrderLines() to List<BaseLine> as:

List<BaseLine> lines = baseDocument.getOrderLines(); this will raise uncheked cast warning but project will compile

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM