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:
Why compiler can't infer the element type as BaseLine
.
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.