Why I can not override method using implementation of class as parameter - java

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;
}
}

Related

How to implement a generic recursive interface?

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;
}
}

Subclasses with generics of subclasses

I have some issues with generics. I have a BaseObject with multiple sub-classes as well as a BaseContainer<T extends BaseObject> with sub-classes that correspond with BaseObject sub-classes.
public class TestClass extends BaseClass<BaseContainer<BaseObject>> {
// method signature tied to BaseClass generic
#Override
private BaseContainer<BaseObject> createContainer() {
BaseContainer<BaseObject> container;
// example logic here to determine which container to use
if (Math.random() < 0.5) {
container = new Parent1Container(); // incompatible types
} else {
container = new Parent2Container(); // incompatible types
}
return container;
}
abstract static class BaseObject {}
static class Parent1Object extends BaseObject {}
static class Parent2Object extends BaseObject {}
abstract static class BaseContainer<T extends BaseObject> {
public abstract void foo(T object);
}
static class Parent1Container extends BaseContainer<Parent1Object> {
public void foo(Parent1Object object) {}
}
static class Parent2Container extends BaseContainer<Parent2Object> {
public void foo(Parent2Object object) {}
}
}
public class BaseClass<T extends BaseContainer> {
public abstract T createContainer();
}
I have a method that returns BaseContainer<BaseObject>. Unfortunately, instantiating sub-classes of BaseContainer results in incompatible types error.
I have tried adding casts to the container instantiation, but it leaves ugly unchecked warnings that make me feel like I'm just missing something. I'd like to avoid those and suppress warnings.
If possible, how can I re-write the any of the classes to make the createContainer() method work?
As written here,
Neither List<Number> nor List<Integer> is a subtype of the other, even though Integer is a subtype of Number. So, any method that takes List<Number> as a parameter does not accept an argument of List<Integer>. If it did, it would be possible to insert a Number that is not an Integer into it, which violates type safety.
Since BaseClass is in a library and you cannot modify it, this case cannot be handled cleanly, i.e. as you expected.
Since Parent1Container and Parent2Container are not exactly BaseContainer<BaseObject> but BaseContainer<? extends BaseObject>
you need to change the signatures accordingly:
public class TestClass extends BaseClass<BaseContainer<? extends BaseObject>> {
...
public BaseContainer<? extends BaseObject> createConstructor() {
if (Math.random() < 0.5) {
return new Parent1Container();
} else {
return new Parent2Container();
}
}
...
}
BaseContainer<BaseObject> makes reference to all those BaseContainer (including extending classes) instances that are able to "handle" any BaseObject, where handle is a blanket-term for all the operations it may do with that type-argument.
In contrast BaseContainer<? extends BaseObject> refer to those BaseContainer instances that are meant to handle a subset of all BaseObject where the top parent class is unknown (thus the ?). It that ? happens to be BaseObject then these two sets would be equivalent.
If your case ? can be either Parent1Object or Parent2Object and so you cannot do better than just leave it as ?.

Partial Generics in Java

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> {

Java Generics: override method that differs in parameterized return type

I come from .Net and I'm pretty new to Java development so maybe that's a weird question:
I have a class hierarchy like:
Superclass implements GenericInterface<Superclass>
^
|
Subclass
where GenericInterface is pretty straight forward:
public interface GenericInterface<T> {
OtherGenericInterface<T> getOther();
}
and OtherGenericInterface finally uses the type parameter:
public interface OtherGenericInterface<T> {
List<Object> processType(T left, T right);
}
now when I try to implement the the interface in Superclass I simply return an anonymous type:
public class Superclass implements GenericInterface<Superclass> {
#Override
public OtherGenericInterface<Superclass> getOther() {
return new OtherGenericInterface<Superclass>() {
#Override
public List<Object> processType(T left, T right) {
...
}
};
}
}
That works fine so far but now I try to override the method in the Subclass:
public class Subclass extends Superclass (implements GenericInterface<Subclass>) {
#Override
public OtherGenericInterface<Subclass> getOther() {
...
}
}
And in there, I can not override the method with my more specific return type. Even if I re-implement the interface and declare the method in the Superclass as final it is not possible.
So my question is: Why isn't OtherInterface<MoreSpecificType> a more specific, or at least the same type (due to type erasure) because that would be the requirement to override the method right?.
This demonstrates a common misconception with Java generics - believing that a match of a class will also match subclasses (like types of parameters). That is not the case. Java generics are designed to ensure that the types match exactly. If you want wriggle room you must specify and define what room you want and how much.
Here's a version that allows you to do what you want by exactly specifying the signature as <T extends Superclass>. This may not be exactly what you are looking for but I hope it points you in the right direction.
public interface OtherGenericInterface<T> {
List<Object> processType(T left, T right);
}
public interface GenericInterface<T> {
OtherGenericInterface<T> getOther();
}
public class Superclass<T extends Superclass> implements GenericInterface<T> {
#Override
public OtherGenericInterface<T> getOther() {
return new OtherGenericInterface<T>() {
#Override
public List<Object> processType(Superclass left, Superclass right) {
return null;
}
};
}
}
public class Subclass extends Superclass {
#Override
public OtherGenericInterface<Subclass> getOther() {
return null;
}
}

How to specify the same Type of class for a returned value in an interface method?

I'm creating a new interface in Java, and I want to create a method that returns de same type of the class that implements the interface.
Example:
public interface ModelInterface {
public (TypeOfClass) getAll();
}
public class Object1 implements ModelInterface {
public Object1 getAll(){
}
}
public class Object2 implements ModelInterface {
public Object2 getAll(){
}
}
How I can accomplish this?
Java has the feature of covariant return types. This means that subclasses can specify a subclass of the method's return type when overriding/implementing the method. It's as simple as
public interface ModelInterface {
public ModelInterface getAll();
}
public class Object1 implements ModelInterface {
public Object1 getAll(){
// implement here
}
}
public class Object2 implements ModelInterface {
public Object2 getAll(){
// implement here
}
}
This tutorial provides an explanation for covariant return types.
Suppose that you have a class hierarchy in which ImaginaryNumber is a subclass of java.lang.Number, which is in turn a subclass of Object.
Now suppose that you have a method declared to return a Number:
public Number returnANumber() {
...
}
The returnANumber method can return an ImaginaryNumber but not an Object. ImaginaryNumber is a Number because it's a subclass of Number. However, an Object is not necessarily a Number — it could be a String or another type.
You can override a method and define it to return a subclass of the original method, like this:
public ImaginaryNumber returnANumber() {
...
}
This technique, called covariant return type, means that the return type is allowed to vary in the same direction as the subclass.
Note: You also can use interface names as return types. In this case, the object returned must implement the specified interface.
You can approximate such a return type in an interface by using generics
interface Foo<T extends Foo<T>> {
T method();
}
This way you are reminded by the compiler that the generic type must be compatible to a type that implements Foo This type might be Foo itself or any other type that implements this interface. When using:
class Bar implements Foo<Bar>
all of your methods are however forced to return Foo as expected.

Categories