I have an abstract Class Monitor.java which is subclassed by a Class EmailMonitor.java.
The method:
public abstract List<? extends MonitorAccount> performMonitor(List<? extends MonitorAccount> accounts)
is defined in Monitor.java and must be overridden in EmailMonitor.java.
I currently have the method overridden in EmailMonitor.java as follows:
#Override
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
//...unrelated logic
return emailAccounts;
}
However, this produces the compile time error:
Name clash: The method performMonitor(List<EmailAccount>) of type EmailMonitor has the same erasure as performMonitor(Lis<? extends MonitorAccount> emailAccounts) of type Monitor but does not override it
EmailAccount is a subclass of MonitorAccount, so (in my mind at least) overriding it in this way makes perfect sense. Seeing as the compiler is not happy with my logic though, How should I go about this correctly while still keeping my compile time checks to make sure that all calls to EmailMonitor.performMonitor() receive Lists of EmailAccount rather than some other type of MonitorAccount?
No, it's not overriding it properly. Overriding means you should be able to cope with any valid input to the base class. Consider what would happen if a client did this:
Monitor x = new EmailMonitor();
List<NonEmailAccount> nonEmailAccounts = ...;
x.performMonitor(nonEmailAccounts);
There's nothing in there which should give a compile-time error given your description - but it's clearly wrong.
It sounds to me like Monitor should be generic in the type of account it can monitor, so your EmailMonitor should extend Monitor<EmailAccount>. So:
public abtract class Monitor<T extends MonitorAccount>
{
...
public abstract List<? extends T> performMonitor(
List<? extends T> accounts);
}
public class EmailMonitor extends Monitor<EmailAccount>
{
#Override
public abstract List<? extends EmailAccount> performMonitor(
List<? extends EmailAccount> accounts)
{
// Code goes here
}
}
You might want to think carefully about the generics in the performMonitor call though - what's the return value meant to signify?
Here is my own solution. I suspect this is the same thing Jon Skeet was trying to get at... without the typo (see my comment in reply to his answer).
the Monitor.java class:
public abstract class Monitor <T extends MonitorAccount> {
...
public abstract List<T> performMonitor(List<T> accounts);
..
}
EmailMonitor.java
public class EmailMonitor extends Monitor<EmailAccount> {
...
public List<EmailAccount> performMonitor(List<EmailAccount> emailAccounts) {
..//logic...logic...logic
return emailAccounts;
}
...
}
In this configuration, EmailMonitor.performMonitor() will always check at compile time that it receives a list of EmailAccount rather than any of my other types FTPAccount, DBAccount, etc... It's much cleaner than the alternative, which would have been receiving/sending a raw list and then having to coerce it the required type resulting in potential runtime type casting exceptions.
Related
I know that I can't do this:
public abstract class DTODomainTransformer<T, S> {
public abstract S transform(T);
public abstract T transform(S);
}
Because I get the compiler complaint:
Method transform(T) has the same erasure transform(Object) as another method in type Transformer<T,S>
I understand that is because both T and S could be extending same class. So doing this way i can tell him "No, they are not the same, so take it easy"
public interface Transformer<T extends AbstractDTO , S extends AbstractDomain> {
public abstract S transform(T object);
public abstract T transform(S object);
}
Then, my question is, is there any way to tell the compiler that T and S extend from different classes without telling which ones in concrete? I mean, in this last case, I've specified which classes had to be T and S (extending respectively). But what if I want it more generic and not specify them? I'd like to tell the compiler, "Hey, compiler, T and S are not the same! They are different classes. I don't know exactly which classes they are, but I'm sure that they are different".
There's not an obvious way. (Although you can build one, as I show below.)
This overload rule is due to a limitation of how the supertype (in this case, interface) that declares the overloads gets translated (by erasure) to bytecode.
If there's a generic parameter declared T, a method that uses T in its signature will have bytecode generated as the upper bound of T, for example
class Generic<T> {
void work(T t) {}
}
will get erased to
class Generic {
void work(Object t) {}
}
and
class Generic<T extends Number> {
void work(T t) {}
}
will get erased to
class Generic {
void work(Number t) {}
}
This is how the bounded example works, because the overloads erase differently.
public interface Transformer {
public abstract AbstractDomain transform(AbstractDTO object);
public abstract AbstractDTO transform(AbstractDomain object);
}
But without specific bounds, what erased bytecode should be generated for the overloaded methods?
So your T and S being different on the subtype is not what's important. What is important is the known declared bounds which get translated to erased bytecode for the supertype class.
A possible solution could use marker interfaces.
interface TransformT {}
interface TransformS {}
interface Transformable extends TransformT, TransformS {}
interface Transformer<T extends TransformT, S extends TransformS>
T transform(S s);
S transform(T t);
}
abstract class AbstractDTO implements Transformable {}
abstract class AbstractDomain implements Transformable {}
new SomeTransformerImpl<AbstractDTO, AbstractDomain>()
But I don't necessarily recommend doing this. It seems elaborate to me, although interesting. It depends on how complicated the actual class hierarchy is.
What Louis suggested in the comments is much simpler: give the methods different names.
I am a bit baffled about Java type checking:
I have a static method declared as:
public static void register(EClass eClass, Class<? extends Page<EObject>> pClass) { ... }
I call it as:
Page.register(HyconmdePackage.Literals.STATION, StationPage.class);
where the second argument is declared as (forget about the first one: it's ok):
public class StationPage extends Page<Station> { ...
public abstract class Page<O> { ...
public interface Station extends Identifiable { ...
public interface Identifiable extends EObject { ...
but I get the error:
The method register(EClass, Class<? extends Page<EObject>>) in the type Page is not applicable for the arguments (EClass, Class<StationPage>)
I tried also declaring Page as:
public abstract class Page<O extends EObject> { ...
but the error remains and I have further problems in class Page.
What's my error? (I hope this is enough to guess the problem; trimming down program to size to have a working example would not be a trivial task)
TiA
StationPage extends Page<Station>, but your method signature requires it to extend Page<EObject>.
Note that, even though Station (indirectly) extends EObject, this does not mean that Page<Station> extends Page<EObject>. So you cannot use Page<Station> when a Page<EObject> is expected.
Declare the method like this:
public static void register(EClass eClass,
Class<? extends Page<? extends EObject>> pClass)
You can ofcourse also use type parameters instead of wildcards:
public static <P extends Page<E>, E extends EObject> register(EClass eClass,
Class<P> pClass)
Simple. Page<Station> is not considered to extend Page<EObject>. Check again the generics tutorial at oracle.com
To see what I mean, look how would this code work if Page<Station> was considered to extend Page<EObject>
public void addItem(Page<EObject> page, EObject item) {
page.add(item);
...
}
addItem(new StationPage(), new EObject());
That would result in an error, since you are attempting to pass an EObject to a method that expects Station. An error that the JVM would not be able to identify as such, since the generics information is not used at runtime. So, the compiler must interpret that as a compilation error, and StationPage does not extend from Page<Object>
Using generics as Jesper instructed
public void addItem(Page<? extends EObject> page, EObject item) {
will allow the compilation, but will put restrictions in the type of operations that you may use with the page parameter (it will not allow to call page.addItem, exactly for the same motive).
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've got problem in my code in Java. I have four(important) Classes:
public class RDOutput extends OutputType
public class RDAnalysis extends AnalysisProperties
Now I'm trying to make a method in Analysis properties:
public abstract void display(ArrayList<? extends OutputType> results);
The main problem list, the objects in the ArrayList will be different subtypes of OutputType. In my class RDAnalysis I try to make specific overriding:
public void display(ArrayList<RDOutput> results) {
but eclipse says: Name clash: The method display(ArrayList) of type RDAnalysis has the same erasure as display(ArrayList? extends OutputType) of type AnalysisProperties but does not override it
I'm not familiar with Java tricks, I tried searching in documentation and I didn't find any solution to this problem.
My question is: Is that trick that I'm doing (Basic type in abstract and Extended in final function) possible in Java (if yes, how can I do that?) or do I have to make some enum to solve this?
I suggest you to introduce generic parameter to your class and use it to parametrize your method:
public abstract class A<T extends OutputType> {
public abstract void display(ArrayList<T> results);
}
public class B extends A<RDOutput> {
public void display(ArrayList<RDOutput> results) {}
}
It's because your display doesn't cover every case of the abstract method. Maybe try something like this :
public class RDOutput extends OutputType {}
public class OutputType {}
public abstract class AnalysisProperties<T extends OutputType> {
public abstract void display(ArrayList<T> results);
}
public class RDAnalysis extends AnalysisProperties<RDOutput> {
#Override
public void display(final ArrayList<RDOutput> results) {
}
}
The problem is that you try to override a method while restricting possible parameters.
=> ArrayList<? extends OutputType> accepts more possible elements than ArrayList<RDOutput> since RDOutput extends OutputType.
You break the rule that says: the concerned subclass method has to encompass at least elements of superclass one and NEVER restrict them.
So compiler avoid to valid this override.
By the way, avoid to type your reference with concrete values like ArrayList.
What about a LinkedList passed as arguments? ... prefer a more generic relevant type like List.
Problem here is that, after type erasure comes into play, the signature of the two methods are undistinguishable: they have the same return type and they can both accept a ArrayList<RDOutput> but the first one (the generic one) can also accept any ArrayList<T extends OutputType>.
This mean that, although the JVM won't be able to choose which one to call at runtime if you pass an ArrayList<RDOutput>, at the same time your display method does not override the abstract one because your method only work for lists of RDOutput, so if you pass a List<T extends OutputType> with T != RDOutput your specific implementation doesn't accept it.
You should consider using a type parameter on the whole class as suggested in other answers, or accept the fact that you won't be able to use any RDOutput specific methods in your display method without a cast.
if a method is expecting ArrayList<? extends OutputType>
ArrayList<RDOutput> cannot be passed to it, as parent type allows any child class of OutputType in arraylist.
consider a code like this
AnalysisProperties properties = new RDAnalysis();
properties.display(arraylist consisting of any child class of OutputType); //this line will cause runtime problems
I suspect this has been asked here (and answered) before, but I don't know how to name the problem. Why can I express the wildcards without problem only when I'm not passing the class itself?
It all boils down to this code. Everything works as expected except for the call to genericsHell(ShapeSaver.class):
interface Shape { }
interface Circle extends Shape { }
interface ShapeProcessor<T extends Shape> { }
class CircleDrawer implements ShapeProcessor<Circle> { }
class ShapeSaver<T extends Shape> implements ShapeProcessor<T> { }
class Test {
void genericsHeaven(ShapeProcessor<? extends Shape> a) {}
void genericsHell(Class<? extends ShapeProcessor<? extends Shape>> a) {}
void test() {
genericsHeaven(new CircleDrawer());
genericsHeaven(new ShapeSaver<Circle>());
genericsHell(CircleDrawer.class);
genericsHell(ShapeSaver.class); // ERROR: The method genericsHell is not applicable for the arguments (Class<ShapeSaver>)
}
}
The type of ShapeSaver.class is Class<ShapeSaver>. When feed it to genericsHell(), compiler needs to check if Class<ShapeSaver> is a subtype of Class<? extends ShapeProcessor<?>, which is reduces to whether ShapeSaver is a subtype of ShapeProcessor<?>. The subtype relation does not hold, the method call fails.
The same thing should be true for #Bohemian's solution. Here the subtype checking occurs at bound checking of T after T is inferred. It should fail too. This appears to be a compiler bug, which somehow misinterprets the rule that Raw is assignable to Raw<X> as if Raw is a subtype of Raw<X>. see also Enum.valueOf throws a warning for unknown type of class that extends Enum?
A simple solution to your problem is to declare
void genericsHell(Class<? extends ShapeProcessor> a)
indeed, ShapeSaver is a subtype of ShapeProcessor, and the call compiles.
That's not just a workaround. There's a good reason for it. Strictly speaking, for any Class<X>, X must be a raw type. For example, Class<List> is ok, Class<List<String>> is not. Because there is really no class that represents List<string>; there is only a class representing List.
Ignore the stern warning that you shall not use raw type. We must use raw types sometimes, given how Java type system is designed. Even Java's core APIs (Object.getClass()) use raw types.
You probably intended to do something like this
genericsHell(ShapeSaver<Circle>.class);
Unfortunately, that's not allowed. Java could have, but did not, introduce type literal along with generics. That created lots of problems for lots of libraries. java.lang.reflect.Type is a mess and unusable. Every library has to introduce their own representation of type system to solve the problem.
You can borrow one, e.g. from Guice, and you'll be able to
genericsHell( new TypeLiteral< ShapeSaver<Circle> >(){} )
------------------
(learn to skip the craps around ShaveSaver<Circle> when reading the code)
In the method body of genericsHell(), you'll have full type information, not just the class.
Typing the genericsHell method allows it to compile:
static <T extends ShapeProcessor<?>> void genericsHell(Class<T> a) {}
EDITED: This allows the compiler to specify from context, or by coding an explicit type, that the ShapeProcessor is not literally any ShapeProcessor, but the same type as the one passed as a parameter. If the call was explicitly typed, (which the compiler does under the covers) the code would look like this:
MyClass.<ShapeSaver>genericsHell(ShapeSaver.class);
Which interestingly, gives a type warning, but still compiles. The explicit type is not required however because sufficient type information is available from the parameter to infer the generic type.
Your question is missing some declarations, so I added them in to create a Short Self-Contained Correct Example - ie this code compiles as-is
static interface Shape { }
static interface Circle extends Shape { }
static interface ShapeProcessor<T extends Shape> { }
static class CircleDrawer implements ShapeProcessor<Circle> { }
static class ShapeSaver<T extends Shape> implements ShapeProcessor<T> { }
static void genericsHeaven(ShapeProcessor<? extends Shape> a) { }
// The change was made to this method signature:
static <T extends ShapeProcessor<?>> void genericsHell(Class<T> a) { }
static void test() {
genericsHeaven(new CircleDrawer());
genericsHeaven(new ShapeSaver<Circle>());
genericsHell(CircleDrawer.class);
genericsHell(ShapeSaver.class);
}