public class IRock
{
public List<IMineral> getMinerals();
}
public class IMineral { ... }
public class SedimentaryMineral implements IMineral { ... }
public class SedimentaryRock implements IRock
{
private List<SedimentaryMineral> minerals;
#Override
public List<SedimentaryMineral> getMinerals()
{
return minerals;
}
}
Getting a compiler error:
Type mismatch: cannot convert from List<SedimentaryMineral> to List<IMineral>.
I understand that I can't convert an impl back to its API interface (because an API is just than - an API). But I'm confused as to why I'm getting a compiler error! Shouldn't Java honor the fact that SedimentaryMineral is an impl of IMineral and allow this?!?
Along with an explanation as to why I'm getting this compiler error, perhaps someone could point out why my approach here is "bad design" and what I should do to correct it. Thanks in advance!
Imagine if this compiled:
List<SedementaryMineral> list = new ArrayList<>();
list.put(new SedimentaryMineral());
List<IMineral> mineralList = list;
mineralList.add(new NonSedimentaryMineral());
for(SedementaryMineral m : list) {
System.out.println(m); // what happens when it gets to the NonSedimentaryMineral?
}
You have a serious issue there.
What you can do is this: List<? extends IMineral> mienralList = list
The problem is that Java generics are not covariant; List<SedimentaryMineral> does not extend/implement List<IMineral>.
The solution depends on precisely what you wish to do here. One solution would involve wildcards, but they impose certain limitations.
Here is what will work for you:
interface IRock
{
public List<? extends IMineral> getMinerals();
}
interface IMineral { }
class SedimentaryMineral implements IMineral { }
class SedimentaryRock implements IRock
{
private List<SedimentaryMineral> minerals;
public List<? extends IMineral> getMinerals()
{
return minerals;
}
}
Here I am using wildcard to denote that I allow list of everything that extends the basic interface to be returned from getMinerals. Note that I also changed some of your classes to interfaces so that everything will compile (I also removed the accessors of the classes so that I can put them in a single file, but you can add them back).
First, your code would work if you done something like
...
public interface IRock
{
public List<? extends IMineral> getMinerals();
}
...
Second, you can't do this directly because you wouldn't be able to guarantee type safety from what you insert inside your list. So, if you want anything that could extend Mineral inside your rock, do what I showed above. If you want that only a specific type of be inserted inside a rock, do something like
public interface IRock<M extends IMineral> {
public List<M> getMinerals();
}
public class SedimentaryRock implements IRock<SedimentaryMineral> {
public List<SedimentaryMineral> getMinerals()
{
return minerals;
}
}
You need to understand why this cannot work in general, and why it is a good thing to have the compiler complain here.
Assuming we have a class ParkingLot implements Collection<Cars> and since Car extends Vehicle, this would automatically make the ParkingLot also implement Collection<Vehicle>. Then I could put my Submarine into the ParkingLot.
Less funny, but simpler speaking: a collection of apples is not a collection of fruit. A collection of fruit may contain bananas, while a collection of apples may not.
There is a way out of this: using wildcards. A collection of apples is a collection of "a particular subtype of fruit". By forgetting which kind of fruit it was, you get what you intended: you know it's some kind of fruit you get out. At the same time, you can't be sure that you are allowed to put in arbitrary fruit.
In java, this is
Collection<? extends Fruit> collectionOfFruit = bagOfApples;
// Valid, as the return is of type "? extends Fruit"
Fruit something = collectionOfFruit.iterator().next();
// Not valid, as it could be the wrong kind of fruit:
collectionOfFruit.put(new Banana());
// To properly insert, insert into the bag of apples,
// Or use a collection of *arbitrary* fruit
Let me emphasize the difference again:
Collection<Fruit> collection_of_arbitrary_fruit = ...;
collection_of_arbitrary_fruit.put(new Apple());
collection_of_arbitrary_fruit.put(new Banana());
Must be able to store any fruit, apples and bananas.
Collection<? extends Fruit> collection_of_one_unknown_kind_of_fruit = ...;
// NO SAFE WAY OF ADDING OBJECTS, as we don't know the type
// But if you want to just *get* Fruit, this is the way to go.
Could be a collection of apples, a collection of banananas, a collection of green apples only, or a collection of arbitary fruit. You don't know which type of fruit, could be a mix. But they're all Fruit.
In read-only situations, I clearly recommend using the second approach, as it allows both specialized ("bag of apples only") and broad collections ("bag of mixed fruit")
Key to understanding this is to read Collection<A> as Collection of different kind of A, while Collection<? extends A> is a Collection of some subtype of A (the exact type however may vary).
Related
Let's say I have the following domain model, which I simplified a little bit just for illustration purposes.
public abstract class JsonSerializer<T> {
public abstract JsonElement toJsonElement(final T object, final Locale locale);
public JsonArray toJsonArray(final Collection<T> objects, final Locale locale) {
return objects.stream().map(t -> toJsonElement(t, locale)).collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
}
}
public class FruitJsonSerializer<T extends Fruit> implements JsonSerializer<T> {}
public abstract class Fruit {}
public class Banana extends Fruit {}
public class Apple extends Fruit {}
Then, when I want to serialize any fruit, I do:
FruitJsonSerializer serializer = new FruitJsonSerializer();
serializer.toJsonElement(new Banana());
serializer.toJsonElement(new Apple());
But I get a warning from the compiler saying that it is an unchecked call to "toJsonElement" as a member of raw type.
How can I avoid this warning without having one serializer declaration per implementation (FruitJsonSerializer<Apple>, FruitJsonSerializer<Banana>, etc)?
Generic parameter should be a concrete class, not a subset of classes. You can declare JsonSerializer<Apple> or JsonSerializer<Banana>. Without a parameter it considered as JsonSerializer<Fruit>.
If you do not want to make FruitJsonSerializer generic then shouldn't write FruitJsonSerializer<T extends Fruit> if. It is enough to inherit it from JsonSerializer<Fruit>. That's my variant:
public static interface JsonSerializer<T> {
JsonElement toJsonElement(final T object);
JsonArray toJsonArray(final Collection<? extends T> objects, Locale locale);
}
public static class FruitJsonSerializer implements JsonSerializer<Fruit> {}
Note that wildcard used for generic parameter of Collection<? extends T>.
You can use the ? wildcard
FruitJsonSerializer<? super Fruit> serializer = new FruitJsonSerializer<>();
Edit: changed extends to super.
Use generics for a class A if
class A can handle multiple different object types with a base class or interface B,
you want to limit the usability of some A instances to specific B subclasses.
E.g. List can handle all Object subclasses, and a List<String> gets limited to String elements by compiler type checking and thus saves you from some types of subtle bugs.
Your JsonSerializer is a valid example calling for generics. But I have my doubts about FruitJsonSerializer.
I suggest to remove the type parameter from FruitJsonSerializer:
public class FruitJsonSerializer implements JsonSerializer<Fruit> {}
Your examples imply that you plan to use the very same FruitJsonSerializer for any kind of Fruit, so there seems to be no need for a FruitJsonSerializer <Apple> or any other specialization.
Maybe I'm wrong, then leave the class definitions as they are, and construct your instances the correct way:
FruitJsonSerializer<Fruit> generalSerializer = new FruitJsonSerializer<>();
FruitJsonSerializer<Apple> applesSerializer = new FruitJsonSerializer<>();
The first one can be used for any Fruit, the second only for Apples.
One more remark: change the toJsonArray() method to read:
JsonArray toJsonArray(final Collection<? extends T> objects, final Locale);
Otherwise you won't be able to pass a List<Apple> to a JsonSerializer<Fruit>.
protected List<? extends ErrorTO> errors = new ArrayList<ErrorTO>();
public abstract Collection<? extends ErrorTO> getErrors();
public void registerError(ErrorTO e) {
errors.add(e);
}
there is a compiling error of line "errors.add(e)", it is expecting some type of "? extends ErrorTO" and does not like ErrorTO? why and ho to fix that? Thanks!
The compiler doesn't know that getErrors will return a Collection<ErrorTo>; it might instead return a Collection<SomeSubclassOfErrorTo>. If you then tried to add an ErrorTo that wasn't of this subclass to the collection, type safety would be violated. For this reason, the compiler will not let you do this.
List<? extends ErrorTO> is not a List that can contain anything that extends ErrorTO.
It is a List of an (unspecified) subclass of ErrorTO.
if MyErrorTO extends ErrorTO, then I can create a List<MyErrorTO> and assign it to errors.
Your code will then try to add an ErrorTO to my List, which is illegal - my List can only contain a specific subclass of ErrorTO
You can't add anything to a List<? extends ErrorTO>. Make it a List<ErrorTO>.
List<? extends ErrorTO> means: a list of some unknow class, which is ErrorTO or extends ErrorTO. So obviously, if you could add something to it, its type-safety would be broken.
Maybe this will help a little. Lets say we have classes
class Fruit {}
class Pear extends Fruit{ void methodA(){} }
class Apple extends Fruit{ void methodB(){} }
and we want to create method like this
public static void method(List<? extends Fruit> list, Fruit f) {
list.add(f); //<-- why is this forbidden?
}
As list argument this method can accept lists like
ArrayList<Fruit>
ArrayList<Apple>
ArrayList<Pear>
If the argument would be new ArrayList<Pear>(); then compiler shouldn't allow to add elements like Fruit or Apple.
But compiler can't know what kind of list he will be dealing with. Because of that lack of knowledge it is impossible to add any elements via List<? extends Fruit> list reference.
I'm using several interfaces with generics types. While combining it together I have some problems when I have to use them from a part of the code that is unaware of the concrete type of the generic parameter.
Suppose I have the following interface:
public interface MyObjectInterface<T extends Number> {}
The object implementing that interfaceare stored in a generic collection with the same generic type:
public interface MyCollectioninterface<T extends Number> {
public void updateObject(MyObjectInterface<T> o);
}
Concrete instances of MyCollectionInterface hold several MyObjectInterface of the same generic parameter:
public class ConcreteCollection<T extends Number> implements
MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<T> o){}
}
Now, I have several questions on how to use these generic interfaces from a client class that is
(and must be) unaware of the concrete type of generics.
Suppose I have the following class:
public class ClientClass{
private MyCollectionInterface<?> collection; //1st possibility
private MyCollectionInterface collection; //2nd possibility
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //this doesn't compile
}
public void foo(MyObjectInterface<? extends Number> o){
this.collection.updateObject(o); //this doesn't compile either
}
public void bar(MyObjectInterface o){
MyObject b = o; //warning
this.collection.updateObject(o); //this compile but with warnings
}
}
First Question :
Considered the fact that ClientClass doesn't care of which concrete type extending Number is the collection, should I declare collection with or without "?" ? If I use the second version I get the following warning:
MyCollectionInterface is a raw type. References to generic type
LatticeInterface should be parameterized
Second Question :
Why method foo doesn't compile?
Third question:
It seems that I need to use bar signature to call updateObject method. Anyway this solution produce a warning while trying to assign the MyObjectInterface parameter, like in the first question. Can I remove this warning?
Last questions:
Am I doing something weird with this generic interfaces and I should refactor my code?
Do I really have to care about all these warnings?
How can I use safety a generic interface from a class where I don't know its concrete type?
Ok, I played a bit with your code and reached a conclusion.
The problem is that your ConcreteCollection (and its interface MyCollectionInterface) declare the method updateObject as receiving an argument of type MyObjectInterface<T> (where T extends Number) - note that the type is a concrete one (not a wildcard).
Now, in your client class you are receiving a collection and storing it as MyCollectionInterface<?> but the instance that is passed to ClientClass' constructor will be of a concrete type, for instance:
new ClientClass(new ConcreteCollection<Integer>());
This means that the method updateObject of that instance would only accept an argument of type MyCollectionInterface<Integer>.
Then, in method foo you are trying to pass a MyObjectInterface<?> to updateObject, but since the compiler doesn't know which generic type your collection accepts (it could be Integer like in my example but it could also be Double or any other type that extends Number), it won't allow any object to be passed.
Long story short, if you declare your reference as MyCollectionInterface<?> you won't be able to call updateObject on it. So you have two choices:
1) Pick a concrete type and stick with it:
private MyCollectionInterface<Number> collection;
public ClientClass(MyCollectionInterface<Number> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<Number> o){
this.collection.updateObject(o); //compiles
}
But then you are limiting the collections you can receive in your constructor (which may not be a bad idea), or:
2) Modify your interface to accept a wildcard type:
public interface MyCollectionInterface<T extends Number> {
public void updateObject(MyObjectInterface<? extends Number> o);
}
public class ConcreteCollection<T extends Number> implements MyCollectionInterface<T> {
List<MyObjectInterface<T>> list;
public void updateObject(MyObjectInterface<? extends Number> o) {}
}
private MyCollectionInterface<?> collection;
public ClientClass(MyCollectionInterface<?> collection){
this.collection = collection;
}
public void foo(MyObjectInterface<?> o){
this.collection.updateObject(o); //compiles
}
Also, note that even in 2) you could still run into the same problem in your implementation of the updateObject method unless you declare your list something like this (with ArrayList for example):
List<MyObjectInterface<? extends Number>> list = new ArrayList<MyObjectInterface<? extends Number>>();
In which case you could as well remove the <T extends Number> from MyCollectionInterface and ConcreteCollection since T isn't used anymore.
#Your last questions:
1) Probably yes
2) You should
3) You can't, if you don't really care which objects you store in the collection, you should ditch generics altogether.
Sorry for the long answer, hope this helps.
I know this isn't a good question to ask and I might get cursed to ask it but I cannot find any place to get help on this question
Below is a Generic class that appeared in my interview question (which I have already failed). The question was to tell what this Class declaration is doing and in what circumstances this could be used for ?
I have very limited understanding of Generic programming but I understand that 'T' is Type and 'extends' here means that the Type should have inherited 'SimpleGenericClass' but I do not understand the '?' at the end and in what circumstances this Class could be potentially used for
public abstract class SimpleGenericClass<T extends SimpleGenericClass<?>> {
}
First, because the class SimpleGenericClass is abstract, it is meant to be subclassed.
Second, it is a generic class which means that inside the class somewhere you will almost assuredly be using the generic parameter T as the type of a field.
public abstract class SimpleGenericClass<T...> {
T x;
}
Now the first interesting thing here is that T is bounded. Because it is declared as T extends SimpleGenericClass<?> it can only be SimpleGenericClass<?> or some subclass of SimpleGenericClass<?>. You also asked about thr ?. That's known as a wildcard and there is a pretty good explanation of it at the Java Tutorial on Wildcards. In your case we would say this is a "SimpleGenericClass of unknown." It is needed in Java because SimpleGenericClass<Object> is NOT the superclass of SimpleGenericClass<String>, for example.
The second interesting thing though is that since T is a SimpleGenericClass of some sort, your class is more than likely defining recursive structures. What comes to my mind are trees (think of expression trees) where SimpleGenericClass is the (abstract) node type, designed to be subclassed with all kinds of specialized node types.
UPDATE This SO question on self-bounded generics might be helpful to you.
UPDATE 2
I went ahead and put together some code that illustrates how this can be used. The app doesn't do anything but it does compile and it shows you how the generic bounds can supply some possibly-meaningful constraints.
public abstract class Node<T extends Node<?>> {
public abstract T[] getChildren();
}
class NumberNode extends Node {
int data;
public Node[] getChildren() {return new Node[]{};}
}
class IdentifierNode extends Node {
int data;
public Node[] getChildren() {return new Node[]{};}
}
class PlusNode extends Node {
NumberNode left;
NumberNode right;
public NumberNode[] getChildren() {return new NumberNode[]{};}
}
The nice thing here is that NumberNode[] is a valid return type for PlusNode.getChildren! Does that matter in practice? No idea, but it is pretty cool. :)
It's not the greatest example, but the question was rather open ended ("what might such a thing be used for?"). There are other ways to define trees, of course.
This really only means that you allow the user of class SimpleGenericClass to parametrize instances of the class with the type T. However, T cannot be any type, but must be a subtype of SampleGenericClass (or SampleGenericClass itself).
In the remainder of the code of class SimpleGenericClass you may use type T in method signatures.
Let's assume for a second that SimpleGenericClass is not abstract. When using it, you could then write:
new SimpleGenericClass<SampleGenericClass<String>>();
I.e. you parametrize SimpleGenericClass with SampleGenericClass and SampleGenericClass with String.
This basically sais: in this class you have a Type placeholder called T, and a restriction on that placeholder, it must be of type SimpleGenericClass or something that extends it. Once you obey that rule you can create instances of your class and give an actual type to T, that later on can be used in methods of that class, something like this:
public class C <T extends Number>{
public void doSomething(T t) {
}
public static void main(String... args) {
//works:
C<Number> c = new C<Number>();
c.doSomething(new Number() {
//Aonimous implementation of number
});
//won't work
//C<Object> c = new C<Object>();
C<Integer> c2 = new C<Integer>();
c2.doSomething(new Integer(1));
//won't work
//c2.doSomething(new Number() {
//Aonimous implementation of number
//});
}
}
The SimpleGenericClass<?> is pretty redundant at this point. If another generic type is needed on this class, you can have more than one (SimpleGenericClass<T extends SimpleGenericClass, T2 extends Whatever>)
By definition it says that the SimpleGenericClass can work on a type <T> which is subclass of SimpleGenericClass.
So I assume there will be some operations which will work on <T>.
Now to see why one would define a template like this - (not much I can think of , really ) may be a scenario where the SimpleGenericClass is an abstract class (just realized it is as per OP :P) and expects that it can work on any concrete classes ?
Guys what do you think ?
I guess you have got the question in this form (T instead of ?):
public abstract class SimpleGenericClass<T extends SimpleGenericClass<T>>
Take a look at this code:
abstract class Foo<SubClassOfFoo extends Foo<SubClassOfFoo>>
{
/** subclasses are forced to return themselves from this method */
public abstract SubClassOfFoo subclassAwareDeepCopy();
}
class Bar extends Foo<Bar> {
public Bar subclassAwareDeepCopy() {
Bar b = new Bar();
// ...
return b;
}
}
Bar b = new Bar();
Foo<Bar> f = b;
Bar b2 = b.subclassAwareDeepCopy();
Bar b3 = f.subclassAwareDeepCopy(); // no need to cast, return type is Bar
The trick going on with Foo<SubClassOfFoo extends Foo<SubClassOfFoo>> is:
Any subclass of Foo must supply a type argument to Foo.
That type argument must actually be a subclass of Foo.
Subclasses of Foo (like Bar) follow the idiom that the type
argument they supply to Foo is themselves.
Foo has a method that returns SubClassOfFoo. Combined
with the above idiom, this allows Foo to formulate a contract that
says “any subclass of me must implement subclassAwareDeepCopy() and
they must declare that it returns that actual subclass“.
To say that another way: this idiom allows a superclass (such as an Abstract Factory) to define methods whose argument types and return types are in terms of the subclass type, not the superclass type.
The trick is done for example in Enum JDK class:
public abstract class Enum<E extends Enum<E>>
Refer here for more details.
Why are java generics so tricky? I thought I finally understood, but eclipse gives me an error at the line in somOtherMethod below using either of the getOuterList methods below.
protected List<?> getOuterList() {
// blah blah
}
protected List<? extends Object> getOuterList() {
// blah blah
}
protected void someOtherMethod() {
...
getOuterList().add((MyObject)myObject); //compile error
...
}
UPDATE: ok - so I understand the error now. It was lack of understanding on my part of what List<?> or List<? extends SomeObject> really means. In the former case, I thought it meant a list that could contain anything. In the latter case, I assumed it was a list of a bunch of objects that extend SomeObject. The proper representation of my understanding would just be List<Object> and List<SomeObject> (w/out the extends). I thought extends helped me solve a problem which they don't. So here's where my real problem lies:
public interface DogKennel {
public List<Dog> getDogs();
}
public class GreyHoundKennel implements DogKennel {
protected List<GreyHound> greyHounds;
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
public List<Dog> getDogs() {
// Is there no way to handle this with generics
// w/out creating a new List?
return getGreyHounds(); //compiler error
}
}
This declaration:
List<?> getOuterList() { }
is telling the compiler "I really don't know what kind of list I'm going to get back". Then you essentially execute
list<dunno-what-this-is>.add((MyObject)myObject)
It can't add a MyObject to the List of something that it doesn't know what type it is.
This declaration:
protected List<? extends Object> getOuterList() { ... }
tells the compiler "This is a list of things that are subtypes of Object". So again, of course you can't cast to "MyObject" and then add to a list of Objects. Because all the compiler knows is that the list can contain Objects.
You could however, do something like this:
List<? super MyObject>.getOuterList() { ... }
and then successfully add a MyObject. That's because now the compiler knows the List is a list of MyObject, or any supertype of MyObject, so it can surely accept MyObject.
Edit: As for your DogKennel example, this code snippet I think does what you want:
protected List<GreyHound> greyHounds;
// We only want a List of GreyHounds here:
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
// The list returned can be a List of any type of Dog:
public List<? extends Dog> getDogs() {
return getGreyHounds();
}
You are saying that the method returns a "List of some unknown type" (which you can't add to, because you can't guarantee that the thing you are adding is a subtype of that type). You actually want to say, a "List of whatever type you want", so you have to make the method generic:
protected <T> List<T> getOuterList() {
// blah blah
}
Okay, I just looked at your update:
It all depends on what you intend to be able to do with the result of getDogs(). If you do not intend to be able to add any items to the list, then getDogs() should return type List<? extends Dog>, and then the problem would be solved.
If you intend to be able to add things to it, and by the type List<Dog> it means that you can add any kind of Dog to it, then logically this list cannot be the same list as greyHounds, because greyHounds has type List<GreyHound> and so Dog objects should not go in it.
Which means that you must create a new list. Keeping in mind of course that any changes to the new list would not be reflected in the original list greyHouds.
You're tripping over the fact that Java generics are not polymorphic on the type parameter.
Talking through your code fragment, let's pull the example apart:
protected List<GreyHound> greyHounds; // List<GreyHound> is fine
/** This method returns a lovely List of GreyHounds */
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
/** Here is the problem. A List<GreyHound> is not a List<Dog> */
public List<Dog> getDogs() {
return getGreyHounds(); //compiler error
}
So your original comment is correct. The two Lists are definitely different with no inheritance between them. So, I would suggest that you investigate these two options:
Try returning a new list as you suggest in your comment. For example, return new ArrayList<Dog>(this.greyHounds);
Do you really need to keep a list of a specific breed of Dog? Perhaps you should define the data member to be a List<Dog> to which you add your specific GreyHounds. I.e., protected List<Dog> greyHoundsOnly; where you manage which dogs are allowed in the kennel via the object's external interface.
Unless you have a good reason to keep a type-specific list, I would think seriously about option 2.
EDIT: fleshing out my suggested options above:
Option 1: Return a new list. Pros: Simple, straightforward, you get a typed list out and it eliminates a thread-safety problem (doesn't expose an internal reference to the world). Cons: seemingly a performance cost.
// Original code starts here.
public interface DogKennel {
public List<Dog> getDogs();
}
public class GreyHoundKennel implements DogKennel {
protected List<GreyHound> greyHounds;
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
// Original code ends here
public List<Dog> getDogs() {
// This line eliminates the thread safety issue in returning
// an internal reference. It does use additional memory + cost
// CPU time required to copy the elements. Unless this list is
// very large, it will be hard to notice this cost.
return new ArrayList<Dog>(this.greyHounds);
}
}
Option 2: Use a different data representation. Pros: plays nicer with polymorphism, returns the generic list that was the original goal. Cons: it's a slightly different architecture which may not fit with the original task.
public abstract class DogKennel {
protected List<Dog> dogs = new ArrayList<Dog>();
}
public class GreyHoundKennel extends DogKennel {
// Force an interface that only allows what I want to allow
public void addDog(GreyHound greyHound) { dogs.add(greyHound); }
public List<Dog> getDogs() {
// Greatly reduces risk of side-effecting and thread safety issues
// Plus, you get the generic list that you were hoping for
return Collections.unmodifiableList(this.dogs);
}
}
a generic type of ? means "some specific type, but i don't know which". anything using a ? is essentially read-only because you can't write to it w/out knowing the actual type.
There is already an accepted answer, however, pls consider the following code modification.
public interface DogKernel {
public List<? extends Dog> getDogs();
}
public class GreyHoundKennel implements DogKernel {
protected List<GreyHound> greyHounds;
public List<GreyHound> getGreyHounds() {
return this.greyHounds;
}
public List<? extends Dog> getDogs() {
return getGreyHounds(); // no compilation error
}
public static void main(String[] args) {
GreyHoundKennel inst = new GreyHoundKennel();
List<? extends Dog> dogs = inst.getDogs();
}
}
Java generics are indeed broken, but not that broken.
BTW Scala fixes this in a very elegant way by providing variance handling.
UPDATE ----------
Please consider an updated snippet of code.
public interface DogKennel<T extends Dog> {
public List<T> getDogs();
}
public class GreyHoundKennel implements DogKennel<GreyHound> {
private List<GreyHound> greyHounds;
public List<GreyHound> getDogs() {
return greyHounds; // no compilation error
}
public static void main(String[] args) {
GreyHoundKennel inst = new GreyHoundKennel();
inst.getDogs().add(new GreyHound()); // no compilation error
}
}