Java Generics & Inheritance: Unable to add to List - java

Suppose I have a List definition as follows.
private List<? extends GeneralBudgetYearBean> budgetYearBeans;
// + Getters/setters...
Why am I unable to generally refer to this List as follows outside this class:
GeneralBudgetYearBean gbyb;
getBudgetYearBeans().add(bgyb);
The error is:
The method add(capture#6-of ? extends GeneralBudgetYearBean) in the type List<capture#6-of ? extends GeneralBudgetYearBean> is not applicable for the arguments (GeneralBudgetYearBean)
This doesn't make sense. Is it because "? extends T" is not the same as "T", and "T" can't be substituted here?
I need to be able to generally manipulate this class without specifics. At some point, there will be an ArrayList of "SUBGeneralBudgetYearBeans" constructed in extending classes, which is why I need to use the "? extends GeneralBudgetYearBean" notation.

According to the PESC principle:
Use extends when only need to get objects and super when only need to add object.
In your case, the
private List<? extends GeneralBudgetYearBean> budgetYearBeans;
is a producer, which means that the list will only be able to produce elements. The reason is that at compile-time the compiler is not aware of the sub-type of GeneralBudgetYearBean, which is why it doesn't let you add elements, since it's not entirely sure whether to allow you or not.
Since you will (at some point) also add SubBudgetYearBean objects (which I believe are subclasses of GeneralBudgetYearBean), you will have to create the list as a consumer. Thus, this will work for you:
private List<? super SubBudgetYearBean> budgetYearBeans;
In this case, you will be able to instantiate budgetYearBean as:
budgetYearBeans = new ArrayList<Object>();
budgetYearBeans = new ArrayList<GeneralBudgetYearBean>();
In both of the cases, you will be able to add both GeneralBudgetYearBean and SubBudgetYearBean objects.

When you use the expression List<? extends GeneralBudgetYearBean> budgetYearBeans;, you tell the compiler that the variable will later receive a List where X will extend GeneralBudgetYearBean. But it cannot know what class it will be, and as such if will not allow you to add anything into it.
You can make the current class generic :
class xxx<T extends GeneralBudgetYearBean> {
private List<T> budgetYearBeans; // getter and setter
Then you will be allowed to do :
T gbyb;
getBudgetYearBeans().add(bgyb);
because now you tell the compiler : you do not know exactly what it will be, but it will be the same thing.

Drop the wildcards, they won't really help you in this case, they just complicate things unless you really know what you are doing.
private List<GeneralBudgetYearBean> budgetYearBeans = ...
public List<GeneralBudgetYearBean> getBudgetYearBeans() {
return budgetYearBeans;
}
Because SUBGeneralBudgetYearBean extends GeneralBudgetYearBean, then there is no problem with either adding them to the list by one...
SUBGeneralBudgetYearBean sgyb = ...
getBudgetYearBeans().add(sgyb);
... or as a list...
List<SUBGeneralBudgetYearBean> sgybs = ...
getBudgetYearBeans().addAll(sgybs);
See? No wildcards are actually needed. :)

Related

Java incompatible types for inherited classes

I'm pretty new to Java, assume these types of questions have been asked before, but after a few hours of search still didn't find the solution for this.
I have an abstract class
public abstract class DBQueryResponse {...}
And two classes inheriting it
public class TransactionKeyResult extends DBQueryResponse {...}
public class SalespersonIdResult extends DBQueryResponse {...}
In another class, I have this function
private DynamoDBQueryExpression<? extends DBQueryResponse> generateQueryExpression() {...}
But whenever I tried to call it somewhere else as such:
DynamoDBQueryExpression<SalespersonIdResult> queryExpression = generateQueryExpression();
DynamoDBQueryExpression<TransactionKeyResult> queryExpression = generateQueryExpression();
It always complains about "Incompatible types", which it expects DBQueryResponse but found else. I always assumed due to polymorphism this is allowed.
The reason I had to use 2 classes is that they are making similar calls to different aws database.
Any advice appreciated. Thanks.
The method should return an exact type rather than wildcard, but the type can be bound:
<T extends DBQueryResponse> DynamoDBQueryExpression<T> generateQueryExpression()
The compiler thinks this is dangerous.Method returns an indeterminate type. Assigning it to a certain type is a sure way to fail compilation.You can continue to use wildcards:
DynamoDBQueryExpression<? extends DBQueryResponse> queryExpression = generateQueryExpression();
DynamoDBQueryExpression<? extends DBQueryResponse> queryExpression = generateQueryExpression();
The casting isn't allowed because you're trying to cast from general to specific. Let's say I have two classes B and C that extend a common class A and a method that returns a list of A(or something that extends A).
List<A> foo = method ();
Is valid because no matter if the implementation of method returns B or C, they both extend A. Now for the one more similar to your example.
List<B> baz = method ();
This is not valid because method's return type is A. Even if you know the implementation will return B. As far as the compiler knows it could also return C or any other child of A that can't be cast to B.

Java generics - When is ? wildcard needed

Say you have some class with type T:
class MyClass<T extends SomeOtherClass> {
....
}
Now, you want to store instances of this class into a collection, but you don't really care about the type. I would express this as following:
private final List<MyClass> entries = new ArrayList<>();
Is there any good reason/advantage to write the following instead?
private final List<MyClass<?>> entries = new ArrayList<>();
Or even:
private final List<MyClass<? extends SomeOtherClass> entries = new ArrayList<>();
I myself can only find a bad reason to do this: whenever the type definition of MyClass changes (for example addition of another type), you have to alter the List<MyClass<?>> or List<MyClass<? extends SomeOtherClass>> definitions all over your code as well.
update
To update my question:
Why isn't the compiler to be able to track the type(s) of MyClass when your write List<MyClass> (or even List<MyClass<? extends SomeOtherClass>>)? He knows that MyClass is defined as MyClass<T extends SomeOtherClass>, so why isn't he able/allowed to do that when you write List<MyClass>?
In other words, why is List<MyClass> not equal to List<MyClass<?>> (or even List<MyClass<? extends SomeOtherClass>>)? The compiler has all the information to make that conclusion himself, afaik.
The ? wildcard is useful when you don't need to refer to the type again and so you don't need to make a specific identifier.
Your first snippet starts with class MyClass<T extends SomeOtherClass>. This is necessary when T is important later on, perhaps to declare a field argument, or return type. For example:
class MyClass<T extends SomeOtherClass> {
private final List<T> aListOfT;
public T getSomething() {
return this.aListOfT.get(0);
}
Since MyClass is a generic type, all references to it should be qualified to avoid avoidable runtime errors. Thus when you declare List<MyClass> you get a compiler warning that you use the raw type MyClass. If you don't care at that location in the code what sort of type MyClass is qualified with, then you use the ? to tell the compiler that you don't care and let it track the type and check all operations for validity.
Your first declaration means, you are not giving any information about your generic data for the future reflection systems, could be used by plugins, which are written for your main program.
The second declaration tells them, that the field contains an Object generics.
The third one is the more specific, it means, that the reflection systems knows, what is this field about detailly.
Using the first type, java will assume that the generic type is Object. The reason for this is, that generics were introduced in version 1.5. Before then the collection-classes stored everything as an object. For compatibility reasons giving no generic parameter means that you are using object.
The second type simply says you don't know or don't care what type it is. This information is preserved when the code gets compiled. So other programmer who might use your code would know that you don't care.
Because of java's type-erasure, there is no difference between these two at runtime.
With the last form you say:
I don't care what it is, but it has to be SomeOtherClass or a derivated type. Which is the same as:
List<MyClass<SomeOtherClass>>
You can also do it the other way around:
List<MyClass<? super SomeOtherClass>>
says that you don't care what type it is, unless it is a supertype of SomeOtherClass.

Why generic type is not applicable for argument extends super class for both?

Here is the problem that I have been being tried to find the solution.
We have two class definitions. One of two extends other one.
class T{}
class TT extends T{}
The requirement is that there should be a list keeps object extends T
List<? extends T> list = new ArrayList<>();
But the problem occures when I try to put a TT object ( barely seems it is a subclass of T )
into the list.
list.add(new TT());
Compilation Error Message
The method add(capture#2-of ? extends Cell) in the type List is not applicable for the arguments (Cell)
You can create a List<T> list = new ArrayList<T>(); directly, this can allow all subtypes of T into the list. This is actually little difficult to understand. when you declare it as
List<? extends T> list = ...
It means that it can allow any unknown subtypes of T into the list. But, from that declaration we cannot ensure which is the exact sub-type of T. so, we can only add null into it
List<? extends T> indicates that anything can comes out of it can be cast to T, so the true list could be any of the following:
List<T>
List<T2>
List<TT>
etc
You can see that even a new T cannot safely be added to such a collection because it could be a List<T2> which T cannot be put into. As such, such List cannot have non null entries added to them.
In this case you may simply want List<T>
So why would you ever use this?!
This contravariance can be useful for method parameters or returns, in which a collection will be read, rather than added to. A use for this could be to create a method that accepts any collection that holds items that are T, or extend T.
public static void processList(Collection<? extends Vector3d> list){
for(Vector3d vector:list){
//do something
}
}
This method could accept any collection of objects that extends Vector3d, so ArrayList<MyExtendedVector3d> would be acceptable.
Equally a method could return such a collection. An example of a use case is described in Returning a Collection<ChildType> from a method that specifies that it returns Collection<ParentType>.
The requirement is that there should be a list keeps object extends T
If you just want a List where you can store objects of any class that extend from T, then just create a List like this:
List<T> list = new ArrayList<T>();
The way you've created a list currently, will not allow you to add anything except null to it.
There are boundary rules defined for Java Generics when using WildCards
**extends Wildcard Boundary**
List means a List of objects that are instances of the class T, or subclasses of T (e.g. TT). This means a Read is fine , but insertion would fail as you dont know whether the class is Typed to T
**super Wildcard Boundary**
When you know that the list is typed to either T, or a superclass of T, it is safe to insert instances of T or subclasses of T (e.g.TT ) into the list.
In your example , you should use "super"
An addition to the other answers posted here, I would simply add that I only use wild cards for method parameters and return types. They're intended for method signatures, not implementations. When I put a wildcard into a variable declaration, I always get into trouble.

Returning Collection<? extends Type> vs Collection<Type>

What is the difference between these two methods?
Collection<Type> getTypes();
vs
Collection<? extends Type> getTypes();
Does it matter if Type is a class or an interface?
Especially, when designing an API, which version would be preferred and why?
Collection<Type> getTypes();
Here, getTypes() must return a Collection<Type> (e.g. ArrayList<Type> or HashSet<Type>).
Collection<? extends Type> getTypes();
Here, getTypes() can return a Collection of anything that is or extends Type, (e.g. ArrayList<SubType> or HashSet<SubType>). So anything that can be returned from the first variant can also be returned from the second. In the second, however, you don't know what the type parameter of the collection actually is; you just know that it extends Type.
As for which should be preferred, it really depends on what you're trying to do, and what makes more sense logically. Bear in mind that when you have <? extends Type>, you don't actually know what ? is, and this can be hindering at times; more often than not the first variant is more suitable. You can use the second variant in a base class and override it in subclasses with something that is more akin to the first, for instance:
#Override
Collection<SubType> getTypes() {
...
}
Returning with a wildcard type is generally discouraged, see the detailed reasons in the Generics FAQ. In short, it can make useless (or less useful) the returned object, because methods with parameters using the type argument can be called with 'null's only. For instance, with the Collection:
Collection<? extends Type> collection = ...
collection.add(null); // OK
collection.add(anInstanceOfType); // Error
In this case, this prevents adding anything to the collection (which is not a bad thing, it seems someone uses this to try to make the returned collection "readonly", here), but in general this can cause problems.
<? extends Type> is a bounding wildcard generic. A collection defined in this way could be of any subclass of type, or Type. ie.
Collection<Type> typeCollection;
//or
Collection<SubType> subtypeCollection;
//where subtype is...
class SubType extends Type
All that matters in this case is that ? is of type Type.
Collection<Type> must be return a collection of Type. ie.
Collection<Type> collection;
Read the tutorials here. for more information. Which you chose will depend on your needs.
Here's an example. I use bounded wildcards when defining renderable item groups. For example.
public class SpriteGroup<T extends Sprite>
This would be a collection for Sprites, or any subclass of Sprite. This is useful because then I can define groups like so:
SpriteGroup<PhysicalSprite> physicalSprites = new SpriteGroup<PhysicalSprite>();
PhysicalSprite physicalSprite = physicalSprites.get(0);
SpriteGroup<ParticleSprite> particleSprite = new SpriteGroup<ParticleSprite>();
ParticleSprite particle = particleSprite.get(0);
Any get/set routines then return the type I specified (PhysicalSprite, ParticleSprite), which is desirable.
If I'd defined it as:
SpriteGroup<Sprite> spriteGroup = new SpriteGroup();
//all I can retrieve is a sprite, gotta cast now...
Sprite sprite = spriteGroup.get(0);
I'd need to cast them to access properties specific to each type of Sprite. Any subclass of SpriteGroup would be restricted likewise.

Java generics confusion

I am a bit of confused about java generics
Here is the code
class Base{}
class Derived extends Base{}
WE can instantiate a list like this
List<? extends Base> list = new ArrayList<Base>();
Why cannot I add a a new item like this
list.add(new Base());
So user cannot use "add" method as far as a wildcard ? in the genetics type?
Thanks
PECS - producer extends, consumer super.
If you replace extends with super, you can add new Base().
List<? extends Base> means "a list that holds instances of any subclass of Base (or Base itself). But it cannot hold instances of two different subclasses.
If you want your list to hold Base and Derived, then use List<Base>. But note that it cannot be later cast to List<Derived>
Just make it
List<Base> list = new ArrayList<Base>();
You shouldn't use wildcards when you know the actual type... just when you're being provided with something with an unknown type.
In such cases, ? extends Base means that the List is only allowed to contain some specific subtype of Base, but you don't know which subtype that is. Because of that, you can't add anything but null to the list.
You can try reading ? as something:
List<? extends Base>
This is "List of something that extends Base". So it is clear that you cannot add a Base (just as you cannot add an Object to a List<String> even when String extends Object.
What you can do in your case is:
List<? super Base>
This is "List of something that is extended by Base". So you can add a Base there (just as you can add a String to a List<Object>, because Object is extended by String.
I think this is a design of Java Generics. The wildcard ? extends Base is compiled to mean that the collection reference can point to a collection object that can hold any ( and all ) types that extend Base.You can write like this as well :
List<? extends Base> _listBaseSubtypes = new ArrayList<Derived>();
Now , with the above line , if you think about it , the below will be obviously an error :
_listBaseSubtypes.add(new Base());
I think Java designers decided to allow the first line of code as valid. In order to avoid the runtime error that the second line of code can cause , it is caught at compile time.
Having said that , the question that comes to mind is : What type of object should be allowed to be added into the collection , given the fact that the actual collection object can be a collection of 'any' derived type ?
Because you can derive as many types as you want , and there cannot be found a single type that is assignment compatible with the type held in the actual collection object ( remember , the collection object could be declared to hold 'any' derived type ) , the simple answer to the question is : None. So , you cannot add any object into the collection through the add interface, because for any object that you may try passing into the add method , there will be complier objection raised on the reason that this type is not compatible with the type that the actual collection object holds.

Categories