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> {
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;
}
}
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;
}
}
Consider the following generic interface:
interface Petlover<T>{
void train(T somePet);
}
I understand that it's possible to provide generic implementations to generic interfaces (e.g., class MalePetLover<T> implements Petlover<T>). But I am having trouble implementing the interface for a specific type only:
class Dogperson implements Petlover<T> {
int age;
void train(String someDog){...};
}
The compilation error is train(String) in Dogperson cannot implement train(T) in Petlover. What would be a right way to handle this?
Since you expect train to accept a String, your class should implement Petlover<String>:
class Dogperson implements Petlover<String> {
int age;
public void train(String someDog) {...};
}
or perhaps the train() method of Dogperson should accept a Dog argument, and then the class would implement Petlover<Dog>.
The subclass that extends a generics class has to conform to the type that it specifies in its own declaration.
You declare : class Dogperson implements Petlover<T> {, so the train() method has to have this signature : void train(T someDog){...};
If you want to have this signature in the subclass:
void train(String someDog){...};
you have to declare a subclass that implements PetLover by specifying the String class as parameterized type :
class Dogperson implements Petlover<String> {
public void train(String someDog){...};
}
You can specify any parameter as T derives from Object in the interface.
For example, if you want to have a Dog as type used in the subclass, you could write it :
class Dogperson implements Petlover<Dog> {
public void train(Dog dog){...};
}
For example, if you want to have a Cat, you could write it :
class Catperson implements Petlover<Cat> {
public void train(Cat cat){...};
}
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.
In a Java application, I'd like to use a generic type parameter which implements an interface which uses a generic parameter itself.
public interface SuperInterface<T> { ... }
public interface MyInterface extends SuperInterface<MyClass> { ... }
public class Worker<T extends SuperInterface<U>> extends SuperWorker<String, Boolean> {
}
However, the class declaration won't work like that. T should be of type MyInterface (or any other interface which implements the SuperInterface) and U should be of type MyClass (or any other class according to the interface).
You have to declare all of the type parameters at the top level. It's annoying, but that's how it is.
public class Worker<U extends MyClass, T extends SuperInterface<U>> { ...
The order of the parameters doesn't matter; you can also do Worker<T extends..., U extends...>. All that matters is that each is declared at the top level of the nested generics.
Here's a complete class:
public class MyClass {
public interface SuperInterface<T>{}
public interface MyInterface extends SuperInterface<MyClass> {}
public class Worker<U extends MyClass, T extends SuperInterface<U>> {}
public void compileTest() {
// just to make sure the declaration compiles
Worker<MyClass, MyInterface> worker = null;
}
}