There are several simple test-case classes:
public interface ListCriteria<T> {
// some stuff here
}
public class UserListCriteria implements ListCriteria<User> {
// implementation
}
public interface Editor<T> {
// sample method 1
List<T> listObjectsTest1(ListCriteria<T> criteria);
// sample method 2
<L extends ListCriteria<T>> List<T> listObjectsTest2(L criteria);
}
And there is an implementation of Editor which Java thinks it does not provide necessary implementation for both sample methods:
public class UserEditor implements Editor<User> {
#Override
public List<User> listObjectsTest1(UserListCriteria criteria) {
//
}
#Override
public List<User> listObjectsTest2(UserListCriteria criteria) {
//
}
}
Both method implementations are wrong. The question is why. Especially for the latter method.
Sure I could do interface Editor<T, L extends ListCriteria<T>>, and that would solve the issue, but I don't want to, I want to understand why I can't use method-level generics here.
The errors you get have nothing to do with generics, because you implement the method with another type than the interface enforces.
The Editor interface defines
List<T> listObjectsTest1(ListCriteria<T> criteria);
Thus the UserEditor must implement in your case
public List<User> listObjectsTest1(ListCriteria<User> criteria) {
You should not mistake the parameter's type with the parameter's generic type. The Editor interface enforces a ListCriteria type. The ListCriteria's generic type is T and T can be bound by a subclass, e.g implements ListCriteria<User>. That is what I mean when I say "errors you get have nothing to do with generics".
I guess what you wanted was
public interface Editor<C, T extends ListCriteria<C>> {
List<C> listObjectsTest1(T criteria);
}
and then the UserEditor can be implemented as
public class UserEditor implements Editor<User, UserListCriteria> {
public List<User> listObjectsTest1(UserListCriteria criteria) {
return null;
}
}
why? Especially for the latter method
The second method in the Editor interface
<L extends ListCriteria<T>> List<T> listObjectsTest2(L criteria);
does not mean that you can implement any type binding of L
The UserEditor must still implement
public <L extends ListCriteria<User>> List<User> listObjectsTest2(L criteria) {
return null;
}
This method defines the generic type L that will be bound when a client invokes the method.
Thus you can invoke the method with any type that is a subtype of ListCriteria<User>.
Your listObjectsTest1(UserListCriteria criteria) function of UserEditor is not overriding the function listObjectsTest1(ListCriteria<T> criteria) of Editor<T> interface because they have two different signature, i.e., essentially the argument type.
The same goes for listObjectsTest2 which was declared in the interface: <L extends ListCriteria<T>> List<T> listObjectsTest2(L criteria); but you have declared it in the UserEditor class as: List<User> listObjectsTest2(UserListCriteria criteria)
So you will need to change the signature to:
class UserEditor implements Editor<User> {
#Override
public List<User> listObjectsTest1(ListCriteria<User> criteria) {
}
#Override
public <L extends ListCriteria<User>> List<User> listObjectsTest2(L criteria) {
}
}
Please read through jls 8.4.8. Inheritance, Overriding, and Hiding for more details.
Related
I have a multi level class structure and want to pass their implementation to a function that can call functions on them, but I get an Incompatible equality constraint: Test.SubDTO2 and Test.SubDTO error.
Here is the code:
public class Test {
abstract class DTO { }
class SubDTO extends DTO implements Interf{ }
class SubDTO2 extends DTO implements Interf{ }
class DAO<T extends DTO> { }
interface Interf { }
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2)); // <- error is in this line
}
static <T extends DTO & Interf> void func(List<DAO<T>> arg) {
}
}
A more detailed example on what I try to achieve:
public class Test {
abstract class DTO {
abstract void func1();
}
class SubDTO extends DTO implements Interf{
#Override
public void func2() {
// comes from Interf
}
#Override
public void func1() {
// comes from DTO
}
}
class SubDTO2 extends DTO implements Interf{
#Override
public void func2() {
// comes from Interf
}
#Override
public void func1() {
// comes from DTO
}
}
class DAO<T extends DTO> {
public T dto() {
return null;
}
}
interface Interf {
void func2();
}
static DAO<SubDTO> daoImpl1;
static DAO<SubDTO2> daoImpl2;
public static void main(String... args) {
func(Arrays.asList(daoImpl1, daoImpl2));
}
static <T extends DTO & Interf> void func(List<? extends DAO<? extends DTO>> arg) {
arg.get(0).dto().func1(); // <- I can't call func2() here
}
}
exact error message:
[ERROR] required: java.util.List<Test.DAO<T>>
[ERROR] found: java.util.List<Test.DAO<? extends Test.DTO>>
[ERROR] reason: inference variable T has incompatible equality constraints Test.SubDTO2,Test.SubDTO
I need the list in the function func to extend DTO and also implement Interf as well, because I call certain functions on them.
Why is this happening? It works fine if I change the signature of the func and pass only one DAO, but I need it to work with multiple.
What are my options here?
I tried it with multiple java versions (1.8+), all the same.
Your function should be declared like this:
static <T extends DTO & Interf> void func(List<DAO<? extends T>> arg) {
Notice that I changed List<DAO<T>> to List<DAO<? extends T>>. This is because the expression Arrays.asList(daoImpl1, daoImpl2) produces a value of type
List<DAO<? extends DTO & Interf>>
(Of course, this isn't real syntax for a type in Java. There's no syntax for intersection types in Java but Java does know about them when doing type inference, and you could have these types in your code if you use var. I use this notation here just for illustrative purposes.)
If you know PECS, you'll know that this is a list of DAOs that produces DTO & Interfs/Ts, but does not consume DTO & Interfs/Ts. If you are lost at this point, please go read the PECS post - it's great. See also: Difference between <? super T> and <? extends T> in Java
The reason why it does this is quite intuitive. Imagine if DAO is just a container for a T.
static class DAO<T extends DTO> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
If Arrays.asList(daoImpl1, daoImpl2) had produced a list of DAO<DTO & Interf> (with no extends or super), you'd be able to call getT and setT on elements of the list! And being able to call setT is especially dangerous you see - you'd be able to do this:
// suppose arg is a List<DAO<DTO & Interf>>
arg.get(someRandomNumber).setT(new SubDTO());
What if someRandomNumber happens to be 1, and we get the second element, which is a DAO<SubDTO2>? Putting a SubDTO inside that destroys the whole type-safety of generics.
The only type-safe thing to do on elements of such a list like [daoImpl1, daoImpl2] is to use them as producers of DTO & Interfs, hence the type is marked ? extends DTO & Interf. This means that if you have any methods on DAO that takes in a T, you won't be able to call them on elements of this list*.
Also note that, just in case I was not clear, it is not the list that is only a producer - the list is both a producer and consumer of DAOs. It's just that the DAOs in the list are producers of their Ts.
* except by passing nulls.
I have simple abstract structure
public abstract class Data<A extends Serializable> {
}
and then String implementation of this class
public class StringData extends Data<String> {
}
then I have Interface:
public interface Testicek<A extends Serializable> {
public abstract Data<A> test(Data<A> bla);
}
and now I want to create class which implement this interface:
public class TesticekImpl implements Testicek<String> {
// OK
#Override
public StringData test(Data<String> bla) {
return null;
}
// compilation error
//#Override
//public StringData test(StringData bla) {
// return null;
//}
}
Why I can not use my StringData class as parameter and it only works in return type ? Signatures of return type and parameter are same.
public interface Testicek<A extends Serializable> {
public abstract Data<A> test(Data<A> bla);
}
Java allows covariant return types, which means that implementations of an interface can return more specific types than the parent interface, because those more-specific types are still instances of less-specific types, and thus they meet the contract of the interface.
However, you can't use more specific parameter types, because the contract of the interface says that it must accept any instance of that type.
The Liskov Substitution Principle tells us that subclasses have to accept parameters that are no more restrictive, and must return values that are no more general.
Java doesn't allow you to use "less restrictive" parameter types, because of the way it resolves methods to invoke at compile time (which is already pretty complicated). This is unnecessarily restrictive from a theoretical point of view, but simpler from a practical point of view.
In terms of you accepting and returning the same type: declare another type variable in your interface:
public interface Testicek<A extends Serializable, D extends Data<A>> {
public abstract D test(D bla);
}
Then your implementation can be:
public class TesticekImpl implements Testicek<String, StringData> {
#Override
public StringData test(StringData bla) {
return null;
}
}
Another case of java generics confusion...
I am defining a hierarchy of interfaces which must include a method to return a list of that interface type. This is a standard use case for the recursive generic pattern (or whatever the name for this is):
interface SuperInter<T extends SuperInter<T>> {
List<T> getEffects();
}
Now when I extends this interface:
interface SubInter extends SuperInter<SubInter> {}
I can implement the sub-interface and have the correct method to implement:
class SubImpl implements SubInter {
#Override
public List<SubInter> getEffects() {
return null;
}
}
and similarly any other interface which uses itself as the generic type will have its implementing class contain a method that returns a list of that interface.
However, I can't implement the super interface type correctly:
class SuperImpl implements SuperInter<SuperInter> {
#Override
public List<SuperInter> getEffects() {
return null;
}
}
Besides raw types warning, I get:
Bound mismatch: The type SuperInter is not a valid substitute for the bounded parameter <T extends SuperInter<T>> of the type SuperInter<T>
I guess because the class does not extends itself. How can I achieve this?
You can declare it as follows:
class SuperImpl implements SuperInter<SuperImpl> {
#Override
public List<SuperImpl> getEffects() {
return null;
}
}
I have an interface that I need to implement. It looks something like this:
public interface SimulationState {
...
public Iterable<VehicleStatus> getVehicleStatuses();
}
I am trying to extend the interface into some sort of a decorator interface as the following:
public interface SimulationStateDec<V extends VehicleStatus> extends SimulationState {
...
#Override
public Iterable<V> getVehicleStatuses();
}
OR
public interface SimulationStateDec<V extends VehicleStatus> extends SimulationState {
...
#Override
public Iterable<? extends VehicleStatus> getVehicleStatuses();
}
Here's the concrete class I'm implementing the interface at:
public class WareHouseState implements SimulationState {
...
#Override
public Iterable<VehicleStatus> getVehicleStatuses() {
return this.vStatuses;
}
}
I am implementing the VehicleStatus interface at a class named VehicleState so i could return the implemented VehicleState
though the Iterable in my concrete class
So at a class in my project I am calling the getVehicleStatuses() method
and I am obligated to cast every element to VehicleState as the following:
public class Gate {
...
private ArrayList<VehicleThread> vehicles;
public Gate(WareHouse wareHouse, GatePriority priority) {
...
this.vehicles = new ArrayList<>();
wareHouseState.getVehicleStatuses().forEach(v -> vehicles.add(new VehicleThread((VehicleState) v, wareHouse)));
sortSameTimeArrivalBy(priority);
}
}
I know I am doing something wrong here, I was wondering if that way of implementation is allowed.
Compiler tells me to change the method in the implemented interface and it's not applicable for my application has to work on a different framework.
I need to return a variety of concrete types that implements the same interface without having to cast every element.
You can't, because when overriding you can only narrow down the return type, and neither Iterable<V> nor Iterable<? extends VehicleStatus> are subtypes of Iterable<VehicleStatus>.
In Java 8 you could perhaps add the new method without overriding and implement the old one as a default (or use abstract class in previous versions):
public interface SimulationStateDec<V extends VehicleStatus> extends SimulationState {
...
Iterable<V> getVehicleStatusesDec();
default Iterable<VehicleStatus> getVehicleStatuses() {
return (Iterable<VehicleStatus>) getVehicleStatusesDec();
}
}
This should be safe because Iterable<T> doesn't have any methods which take T as argument: it "should" be covariant except Java doesn't support that; doing the same with e.g. List is a bad idea!
This is how you should use it, since X< A> is not substitutable by X< B > even though A extends B, to simply put Iterable< VehicleStatus> is not replaceable by Iterable< V> where V extends VehicleStatus.Hence, the error that you are changing method return type while overriding
public class VehicleStatus{
}
public interface SimulationState {
Iterable<? extends VehicleStatus> getVehicleStatuses();
}
public interface SimulationStateDec<V extends VehicleStatus> extends SimulationState {
#Override
public Iterable<V> getVehicleStatuses();
}
i have an application with developing datamodel (the app handles old and new data).
Now i want to overwrite the return type of the method with an evolution of the original return type:
public interface Section {
List<Item> getItems();
}
public interface Item {
String getName();
}
public interface ItemEvolution extends Item {
String getEvolution();
}
public interface SectionEvolution extends Section {
List<ItemEvolution> getItems();
}
in this constellation i get an incompatible return type at getItems(), but i don't break the parent interface, cause ItemEvolution extends Item.
How can i handle that?
I am using Java 8
List<ItemEvolution> is not compatible with List<Item> (because you can add an Item to the latter but not the former). This is a common pitfall with generics.
One solution is to use List<? extends Item> as the superclass's return type in Section:
public interface Section {
List<? extends Item> getItems();
}
public interface SectionEvolution extends Section {
// Or List<? extends ItemEvolution> if you might want to override this again.
List<ItemEvolution> getItems();
}
In this case you should use generics.
public interface Section<E extends Item> {
List<E> getItems();
}
public interface Item {
String getName();
}
public interface ItemEvolution extends Item {
String getEvolution();
}
public interface SectionEvolution extends Section<ItemEvolution> {
}
This one nicely explains why your case is not working:
http://docs.oracle.com/javase/tutorial/java/generics/inheritance.html
So List<ItemEvolution> is not a subclass of List<Item> - So you need to use generics with wildcards as described here - actually this article explains exactly your case.
http://docs.oracle.com/javase/tutorial/java/generics/subtyping.html