L4zy
L4zy

Reputation: 337

Java Generics wildcard extends final class

Why does Java doesn't throw any warning when compiling my TestGenerics class, considering that the String class is final and cannot be extended?

import java.util.*;
    public class TestGenerics { 
        public void addStrings(List<? extends String> list) {
          // some code here
        }
    }
}

Upvotes: 13

Views: 1356

Answers (3)

ZhongYu
ZhongYu

Reputation: 19682

The type system does not consider List<String> and List<? extends String> equivalent, even though at the time of compiling, String has no subtypes other than itself, therefore any object that is a List<? extends String> must also be a List<String>.

One explanation is that final is not final - it's ok to remove final from a class and nothing should break: http://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.2

It's not without precedence that the type system takes final into consideration; for example, we cannot cast a String to a Runnable, because the compiler figures that if an object is String, it cannot be some unknown subclass that implements Runnable.

If we want generics also to make reasoning like that and deduce that List<String> and List<? extends String> are equivalent, it'll make typing rules even more complicated.

Upvotes: 0

yshavit
yshavit

Reputation: 43401

Let's say I had a method like this:

public List<? extends T> filterOutNulls(List<T> input) { ...

Granted, not the best signature in the world, but still perfectly legal. What would happen if I passed a List<String> to that method? According to the signature, it returns a List<? extends String>. If Java disallowed that type, it'd be impossible to use this method for List<String> (or at least, it'd be impossible to use the return value).

Secondarily, the extends syntax is still useful in this case, since List<String> and List<? extends String> have different restrictions -- specifically, you can't add anything but a null literal to List<? extends String>. I'll sometimes use ? extends to signify that a collection is read-only (since the only Ts you can pass in are null), and ? super to signify write-only (since you can only get out Ts as Object). This isn't completely fool-proof (you can still call remove methods, pass in nulls, downcast, etc) but serves as a gentle reminder of how the collection is probably meant to be used.

Upvotes: 12

tbodt
tbodt

Reputation: 17007

The compiler doesn't really take note of that fact, because it doesn't matter. Strings are still allowed in the list, and in the final product, the possibility of anything extending String is not found. After erasure, it comes out like this:

public void addStrings(List list)

As you can see, there is now no suggestions of a class extending String. If you do create a class extending String, that will be itself a compile error. There's no need for javac to worry about that.

Upvotes: 7

Related Questions