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;
}
}
Related
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;
}
}
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();
}
So I have an interface -
public interface GenericTranslator <From, To> {
To translate(From from);
}
and have a class that implements it
public class TimeToStringTranslator implements GenericTranslator <Time, String> {
String translate(Time time) { ... }
}
But I now want to have an abstract layer where input type From is Time
// an abstract class with partial generic defined
public abstract class AbstractTimeTranslator<Time, To> implements GenericTranslator<Time, To> {
#Override
To translate(Time time) {
doSomething();
return translateTime(time);
}
protected abstract To translateTime(Time time);
}
// concrete class
public class TimeToStringTranslator extends AbstractTimeTranslator<Time, String> {
String translateTime(Time time) { .... }
}
Is it possible in Java? I tried, Java treats Time as a generic name in AbstractTimeTranslator
If Time is an actual type argument instead of another generic type parameter, then you should not declare Time as a generic type parameter in the class definition of AbstractTimeTranslator; just use it as a type argument in the implements clause.
This only defines the To type parameter in this class.
abstract class AbstractTimeTranslator<To> implements GenericTranslator<Time, To> {
Consequently, you only need to supply one type argument in the extends clause of the concrete subclass.
class TimeToStringTranslator extends AbstractTimeTranslator<String> {
So I have got 2 generic interfaces.
First interface is implemented like this.
public interface First<E>
{
void method(E e)
}
public class FirstImpl implements First<String>
{
void method(String s) { System.out.println(s); }
}
public class FirstImpl2 implements First<Double>
{
void method(Double d) { System.out.println(d); }
}
I need the second interface's (second interface is shown below) generic type to allow only the classes that are used when implementing the first interface, in our case String and Double. Is there any clean way to do this, something like
public interface Second <E, ? extends First<E>>
{
void method(E e);
}
public class SecondImpl <E> implements Second <E, ? extends First<E>>
{
void method(E e) { System.out.println(e); }
}
, so the in Second's generic E would fit only String and Double and all classes that are used to implement First<E>?
Nope. You can not restrict the generic type of the Second in that sense. You can still provide an another type information independently. Say,
class XYZ implements First<Bar> { ... }
an another class may provide an another type information for the Second, like
class ZYX implements Second<Foo, SomeOtherType<Foo>> { ... }
assuming SomeOtherType implements/extends whatever from type First. If you want to bind those two interfaces on their generic type, you can use inheritance between the implementations:
interface First<T> {}
interface Second<T> {}
class Foo<E extends T> implements First<T> {}
class Bar<E extends T> extends Foo<E> implements Second<E> {}
Now, the type E, is associated with the type T, via E extends T.
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.