I have an interface that ensures objects can make copies of themselves:
public interface Duplicable<T extends Duplicable<T>> {
public T duplicate();
}
I now have
class X implements Duplicable<X>
but I also have a class Y that extends X.
This isn't a problem, until I need another generic class:
public class DoStuffWithDuplicable<T extends Duplicable<T>>
I can't use a generic version of DoStuffWithDuplicable using Y, since it does not implement Duplicable<Y> but Duplicable<X> since it inherits it from X.
So I tried
public class DoStuffWithDuplicable<T extends Duplicable<? super T>>
.. but this means later introducing an unsafe cast
(T) obj.duplicate()
in the code body. Also the class parameters are more convoluted and the usage of the class harder to understand. Any ideas how to get around this problem?
I may not have understood your question properly, but I'll give it a go.
First of all, why do you have an interface that extends itself like that?
What you can try is this:
public interface Duplicable<T> {
public T duplicate();
}
Then when you use another class where you want the generic parameter to be Duplicable, you do it like this:
public class X<T extends Duplicable<T>> {
code...
}
Now when you inherit from X, any generic component in the subclasses will have to be Duplicable.
It is not possible to do this in Java.
Assume you call obj.duplicate() on an object of type Y. Then the typesystem can only ensure that it will return an object of type X, since Y implements Duplicate<X>.
But you can just create a DoStuffWithDuplicable<X> and pass Y objects to it.
DoStuffWithDuplicable<X> blub = new DoStuffWithDuplicable<X>();
Y y = (Y) blub.doStuff(new Y());
For return values, the client of your library can just use safe casts, as he probably knows the concrete types.
An other option would be to use unsafe casts in the library and check the types manually:
class DoStuffWithDuplicable<T extends Duplicable<? super T>> {
T doStuff(T obj) {
#SuppressWarnings("unchecked")
T t = (T) obj.duplicate();
if (!t.getClass().equals(obj.getClass()))
throw new ClassCastException("...");
return t;
}
}
Related
In Java, is it possible to create a method / a signature that accepts all non-abstract Class types?
Something a la this:
public Object getInstance(Class<? extends ConcreteClassSuperType> someNonAbstractClass){
//some logic that can safely assume that the Class object is not an interface type nor an abstract class
}
where ConcreteClassSuperType is just a fictional type made up to illustrate my intend. Using ? extends Objecthere does not solve the problem.
Elaboration:
In the case at hand the problem was a bit more specific in that my signature dit not have to accept ALL concrete classes but only those implementing some interface, i.e. I was trying to create a signature that accepts the Class type of a class that implements MyInterface. So one could fx pass MyClass.class, where MyClass implements MyInterface. Two problems occured:
The signature will also accept MyInterface.class (since the generics Class<? extends MyInterface> is not a strict upper bound)
One can pass the class type of another interface that extends MyInterface.
Because classes can have multiple parameters, I think it is easier first just to check if the class is concrete and then implement a means to instantiate it. Like,
public <T> boolean isConcrete(Class<T> c) {
if (c.isInterface() || (c.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT)
return false;
return true;
}
Hope this helps.
EDIT
Sorry just noticed in another comment you could simplify this...
public <T> boolean isConcrete(Class<T> c) {
if (c.isInterface() || Modifier.isAbstract(c.getModifiers()))
return false;
return true;
}
I ran into a problem when trying to specialize a class that implements a generic interface where I wanted to inherit from the same interface as the super class, but with a more specific type argument. The following snippet shows a synthetic but complete example that cannot be compiled. The comment contains the error message from the Java compiler.
interface Producer<T> {
T get();
}
class NumberProducer implements Producer<Number> {
#Override
public Number get() { return null; }
}
// Producer cannot be inherited with different arguments: <java.lang.Integer> and <java.lang.Number>
class IntegerProducer extends NumberProducer implements Producer<Integer> {
#Override
public Integer get() { return null; }
}
In the PECS sense, Producer<T> is a producer, so Producer<Integer> would be a subtype of Producer<Number>, but there's no way to declare that in the definition of Producer<T>. Java does not allow IntegerProducer to inherit from NumberProducer and Producer<Integer> at the same time as IntegerProducer would then inherit from Producer<Integer> and Producer<Number> at the same time.
Is there a standard approach to this limitation, e.g. a pattern that solves the same problem without requiring this kind of inheritance?
Just add a parameter to the super class:
interface Producer<T> {
T get();
}
class NumberProducer<T extends Number> implements Producer<T> {
#Override
public T get() { return null; }
}
class IntegerProducer extends NumberProducer<Integer> { // Implicit: implements Producer<Integer>
#Override
public Integer get() { return null; }
}
Say we had a simple Method gimme.
public static <T> T gimme(Producer<T> p) { return p.get(); }
Within the context of gimme nothing is known about T. It could be Number, Integer or any other reference type. So, due to erasure, the compiler emits an interface call to Producer.get()Object rather than the specific call to, say, IntegerProducer.get()Integer. All types that implement Producer<T> with T != Object also implicitly implement Producer.get()Object. This implicit implementation forwards to the specific implementation. That might be NumberProducer.get()Number or IntegerProducer.get()Integer, but not both. That's why you can't implement the same interface twice.
Other languages allow this via definition site variance, where Producer<Integer> is a subtype of Producer<Number>, but alas, Java does not. The common workaround is to make NumberProducer generic as well.
If you want to ensure that T is of a specific subtype you can use
interface Producer<T extends Number>
Not sure what Producer reall is so I have to guess.
Update:
If I understand you correct then I would say, you need to declare an interface which is a Producer. That's simple.
From this interface i would derive a new interface with the respecitve base type.
i.e.:
interface Producer
{
base functions
};
interface Newproducer<T extends Producer>
{
};
Is this what you had in mind?
I have written a class which is a base class of Class A and implements an interface of Class B.
Now my compiler is giving a wierd kind of error saying that "The return types of functiona from Class A is not compatible with return type of functiona in class B."
My Code is as below,
public class X extends A implements B
{
}
public class A
{
public Enumeration<String> test(){}
}
public interface B
{
public Enumeration<Object> test();
}
Now I can't understand why the compiler is giving such an error since already String is a type of an object, so what i understood is that automatic type conversion should happen in runtime because of that. Am i right? or my conceptual understanding has gone wierd on me?
If you can change the definition of the interface, you can broaden it and get what you want. The return type would be Enumeration<? extends Object>
What you're trying to do is possible in Java. As Ernest stated, an Enumeration is not a subclass of Enumeration, since Java genercis lacks the concept of variance.
Anyway, you can express you intention using type wildcard. You have to change you interface this way:
public interface B
{
public Enumeration<?> test();
}
Now your code compile fine. Just to let you know, you can also restrict your interface to some other type than Object. For example, if you have to build an interface that return Enumerations
of Number:
class X extends A implements B
{
}
class A
{
public Enumeration<Long> test(){return null;}
}
class C
{
public Enumeration<String> test(){return null;}
}
//This doesn't compile! String does not extend Number
/*class Y extends C implements B
{
}*/
interface B
{
public Enumeration<? extends Number> test();
}
String is a subclass of Object, but Enumeration<String> is not a subclass of Enumeration<Object>. If it were, then I could cast an Enumeration<String> to an Enumeration<Object>, then cast it to an Enumeration<Integer>, all without a warning; but when I tried to use it as an Enumeration<Integer>, I'd get ClassCastExceptions.
Note that Java arrays behave as I've described above, and this is widely considered a significant flaw in the design of the language.
If I have:
interface A{ void a(); }
interface B{ void b(); }
I can hava a generic method like this:
class C {
<T extends A & B> void c(T t) {
t.a();
t.b();
}
}
But i can't hava a generic collection like this:
class D{
List<? extends A & B> l;
}
I know that I could make an empty interface E that extends both A and B, and have a List that contains E's... but I'd rather leave my classes marked with just A and B, and not have to have an E. This is even more problematic when there are many more A's and B's that can be combined in 2^n ways.
I would rather be able to define a type on the fly, as a union of interfaces, and have the collections recognize objects that implement all of the interfaces as instances of that type.
Is there a way to do this in Java? I'm open to any kind of work around or hack at this point in order to avoid making a new interface, and tagging my classes with it, just so that they can live together in a collection. Or, if someone could clarify for me why this is impossible, that would be equally appreciated.
public class Foo<T extends A & B> {
private List<T> list;
//getters, setters, etc.
}
As Jeffrey also said somehow, you have to parameterize your class D:
class D<T extends A & B> {
List<T> l;
/**
* this is just a method for the sake of example
*/
public T getSomeMember() {
return l.iterator().next();
}
}
This way you are deferring your choice of the actual type T to the method which actually insntatiates D. If that information is not available even at that point you will have to parameterize that method too with <T extends A & B>:
private <T extends A & B>
void doSomething() {
D<T> d = new D<T>();
T v1 = d.getSomeMember();
A v2 = d.getSomeMember();
B v3 = d.getSomeMember();
}
If there is a field of type D in some class, then that class must know the actual type that extends A & B, or be itself parameterized if it doesn't. In principle you propagate the type parameter up until you know the actual type.
Be warned that this process is likely to become unmanageable for large codes. It may also result in ugly code, but of course that depend on your conception of aesthetics.
I have the following 2 interfaces accordingly to abstract factory pattern:
public interface GenericObjectInterface<T extends Number>{
public T getResult();
}
public interface AbstractFactoryInterface{
public <T extends Number> GenericObjectInterface<T> createGenericObject();
}
I have an abstract class implementing GenericObject, but it's still unaware of the concrete type (it does only generic operations on Number):
public abstract class GenericAbstractClass<T extends Number> implements GenericObjectInterface<T>{ }
Then I have a series of concrete class extending that perform generic parameter substitution:
public class IntegerObject extends GenericAbstractClass<Integer>{
public Integer getResult(){}
}
....
Now, from inside an implementation of the factory I build the concrete type, that's implementing GenericObjectInterface but has lost it's generic parameter:
public class ConcreteFactory{
public <T extends Number> GenericObjectInterface<T> greateGenericObject(Class<T> c){
if (c.class.isInstance(Integer.class)){
IntegerObject obj = new IntegerObject();
//I would like to return obj
GenericObjectInterface<T> a = new IntegerObject(); //errror
GenericAbstractClass<T> a = new IntegerObject(); //errror
return a;
}else if (c.class.isInstance(Double.class)){
}
}
}
I would like to return obj that implements GenericObjectInterface but I don't know how can I do it.
how can I solve this?
I'm used to abstract factory but I've never used it with generics. Am I doing some mistakes in interpreting the pattern?
If your method returns an IntegerObject why don't you just return GenericObjectInterface<Integer>? You already know the parameter type.
In that case, just add a generic parameter to AbstractFactoryInterface, too:
public interface AbstractFactoryInterface<T extends Number> { ... }
public class ConcreteFactory implements AbstractFactoryInterface<Integer> { ... }
In your implementation the type of T would be inferred from the assignment, and thus you could do this:
GenericObjectInterface<Double> g = new ConcreteFactory().greateGenericObject();
In that case T would be Double but you'd use Integer internally, resulting in this:
GenericObjectInterface<Double> a = new IntegerCell();
Since the compiler can't ensure that T will always be of type Integer it won't allow you to do that assignment.
Abstract factory is characterized by the factory method returning an interface or abstract class reference instead of the concrete reference. It does not extend to type parameters.
Think of it this way: should you be able to do this?
public class ConcreteListFactory {
public <T> List<T> createList() {
return new ArrayList<String>();
}
}
What if the caller wanted a List<Integer>?
If you want your factory to return a generified type, you should have your concrete class accept the type parameter. Otherwise have your factory method return a GenericObjectInterface<Integer>.
Alternatively, you could have your method accept a type token (Integer.class). For example:
public <T extends Number> GenericObjectInterface<T> createGenericObject(Class<T> clazz) {
if ( clazz.equals(Integer.class) ) {
return (GenericObjectInterface<T>) new IntegerObject();
}
}
This will result in an unchecked cast warning but you can prove to yourself that it is safe, and thus suppress the warning or ignore it.
Generally, factories are not implemented as generics because you can't examine the type of the generic to determine the type of object to create (you can't do T.getClass) which is why #Mark's example causes the class to be passed in as an argument.
I think, more usually you would have multiple concrete factories. One for each Number type that you intend to support.
public interface AbstractFactoryInterface<T extends Number> {
public GenericObjectInterface<T> createGenericObject();
}
class IntegerFactory implements AbstractFactoryInterface<Integer>...
class LongFactory implements AbstractFactoryInterface<Long>...
You could then create a Map<Class, AbstractFactoryInterface>...
Map<Class, AbstractFactoryInterface> myMap = ...;
myMap.put(Integer.class, new IntegerFactory());
myMap.put(Long.class, new LongFactory ());
casting is perfectly fine here. if c==Integer.class, then T=Integer, casting GOI<Object> to GOI<T> is absolutely correct. It is a checked cast because you have checked that T=Integer before casting, therefore the unchecked warning can be legitimately suppressed.