I am unable to compile a method which needs to override a method from an abstract class supertype which uses generics for one of the parameters. The compiler complains that the extending class' setRef() method does not override a method from the supertype.
Parent Abstract Class:
public abstract class AbsClass<Q extends Interf> {
public abstract Ref<? extends AbsClass<Q>> getRef();
public abstract <M extends AbsClass<Q>> void setRef(Ref<M> newRef);
}
Ref is:
public interface Ref<M extends AbsClass<? extends Interf>> { }
and Interf is:
public interface Interf { }
Extending Child Class (setRef() doesn't compile):
public class ChildClass extends AbsClass<InterfImpl> {
#Override
public Ref<ChildClass> getRef() {
return null;
}
#Override
public <M extends ChildClass> void setRef(Ref<M> newRef) {
return null;
}
}
I have also tried using wildcards, and received same error. With wildcards, the abstract class' setRef() is:
public abstract void setRef(Ref<? extends AbsClass<Q>> newRef);
and the extending class' setRef() is:
public void setRef(Ref<ChildClass> newRef)
or even:
public void setRef(Ref<? extends ChildClass> newRef)
The only way I can get it to compile is if the extending class' setRef() uses the abstract class' type:
public <M extends AbsClass<Interf>> void setRef(Ref<M> newRef)
But I would like to limit the typing of the newRef parameter to be Ref<ChildClass> or subtypes, so this isn't perfect. How can I get my extending class to only allow ChildClass or its subtypes for the setRef() method's newRef parameter? Part of my confusion is that the ChildClass' getRef() return value handles the generic typing just fine, and the same "signature" on setRef()'s parameters fails to compile. Help? Thanks!
The problem with setRef is that you could access an instance of ChildClass through a variable of type AbsClass<? extends Interf> and thus the parameter type for setRef would look like <M extends AbsClass<? extends Interf>> which again could be any M but which also doesn't match <M extends AbsClass<Q>> since Q has been defined to be InterfImpl in your case.
You could change ChildClass to this:
public <M extends AbsClass<InterfImpl>> void setRef(Ref<M> newRef)
but this would still allow any M and you can't just use Ref<ChildClass> because what I said above, i.e. the compiler wouldn't know about Ref<ChildClass> if you used a variable of type AbsClass<InterfImpl> or even AbsClass<? extends InterfImpl>.
One way to allow only for ChildClass parameters would be to use ChildClass in the generic type as well, e.g. like this:
public abstract class AbsClass<Q extends Interf, M extends AbsClass<Q, M>> {
public abstract Ref<M> getRef();
public abstract void setRef(Ref<M> newRef);
}
public class ChildClass extends AbsClass<InterfImpl, ChildClass> {
public Ref<ChildClass> getRef() { return null; }
public void setRef(Ref<ChildClass> newRef) { }
}
You are getting an error because in AbsClass.setRef(), your parameter is of type Ref<? extends AbsClass<Q>>
But in your ChildClass.setRef() the parameter is of type Ref<? extends ChildClass>.
For overriding, a subclass should have the same typed parameters in the method as it's parent (before type erasure when using Generics).
Related
I have such class:
public abstract class Test<T extends List<?>> {
public abstract void handle(? arg);// ? - obviously won't work
}
Is there any way to "know" the type of list element in the Test's subclass?
You could use a named generic type parameter instead of ?.
Something like this:
public abstract class Test<E, T extends List<E>> {
public abstract void handle(E arg);
}
The below #Override annotation indicates that I am not overriding the method defined in the interface. How do I use generics with my concrete class so that it overrides the interface method?
public interface AInterface<T extends MyType> {
void do(T thing)
}
public abstract class BaseMyClass implments AInterface {
// other stuff
}
// AType extends MyType
public class MyClass extends BaseMyClass <AType> {
#Overide
public void doThing(AType atype) {
}
}
BaseMyClass is implementing the rawtype of AInterface, you either need to extend the generic to the abstract class itself or define it:
public abstract class BaseMyClass implments AInterface<AType>
public abstract class BaseMyClass<E extends MyType> implments AInterface<E>
BaseClass<AType> (assuming you meant BaseMyClass) isn't actually giving you a AInterface<AType>
This answer no doubt exists on SO, but I haven't found the right combination of search terms to come up with it.
I have a method that I want to take a parameter that is of class A, but also implements interface B. How do I do it?
e.g.
public class MySubclassWithInterface extends MyClass implements MyInterface { }
public class MySubclass extends MyClass { }
public class MyInterfaceClass implements MyInterface { }
public class MyOtherSubclassWithInterface extends MyClass implements MyInterface { }
Out of the three classes above, I only want my method to accept an object that is MyClass and implements MyInterface, in other words, either MySubclassWithInterface or MyOthersubclassWithInterface but not MySubclass or MyIntefaceClass
I very sheepishly tried the following which obviously failed:
public void myMethod( (MyClass MyInterface) parameterName) {
...
}
Thanks for your help in advance.
You can express this with a generic type as in the following signature:
<T extends MyClass & MyInterface> void m(T p)
The rule is that the first type must be a class or an interface and any following parameter must be an interface type.
I thought I understood how to do this but I'm getting some unexpected behavior so apparently I'm missing something. Here's the problem boiled down.
Base Class:
public abstract class Base<T>
{
abstract public void foo(List<? extends T> l);
}
Derived Class:
public class Derived<T> extends Base
{
#Override
public void foo(List<? extends T> l) { return; }
}
The Base class complies fine, but when I compile the Derived class I get:
Derived.java:3: Derived is not abstract and does not override abstract method foo(java.util.List) in Base
public class Derived extends Base
^
Derived.java:5: method does not override or implement a method from a supertype
#Override
^
2 errors
The generics of the parameter List<? extends T> appears to be the cause of the problem. If I replace that part in both signatures with the basic type int it comples fine.
Can anybody tell me what's going on here?
You should do
public class Derived<T> extends Base<T>
You need to specify <T> for Base otherwise you will have to override method by simply declaring List i.e.without generics
You can also pass the type parameter in your class declaration like this:
public class Derived extends Base<SomeConcreteType> {
#Override
public void foo(List<SomeConcreteType> l) {
// ...
}
}
if you no longer need the generic part of the abstract class because you are going to use a concrete type in your derived class. Otherwise you have to do what the other answer stated.
I am trying to create a set up where a set of subclasses override a superclass. This superclass contains an abstract method - the return type of which would ideally be that of the object from which this method was called, such that it effectively behaves like this:
public abstract class SuperClass{
public abstract SuperClass getSelf();
}
public class SubClass extends SuperClass{
#Override
public SubClass getSelf(){
return this;
}
}
I am unsure if such a thing is possible, as I think return types always have to be the same in order for the override to work - however I have been thinking the answer, should one exist, lies somewhere along this line...
public abstract class SuperClass{
public abstract <? extends SuperClass> getSelf();
}
public class SubClass extends SuperClass{
#Override
public SubClass getSelf(){
return this;
}
}
Thanks for any help.
edit: added extends SuperClass to SubClass, duh
This will work:
public abstract class SuperClass{
public abstract SuperClass getSelf();
}
public class SubClass extends SuperClass{
#Override
public SubClass getSelf(){
return this;
}
}
Notice I've added extends SuperClass to your SubClass definition. The return type of getSelf is referred to as a covariant return type.
How about this:
public abstract class SuperClass<T extends SuperClass<?>> {
public abstract T getSelf();
}
public class SubClass extends SuperClass<SubClass> {
public SubClass getSelf() {
return this;
}
}
I know it's quite repetitive and nothing bounds the type to be the same SubClass instance, because also AnotherSubClass would satisfy the bound, but at least it should do the trick.
Here is how to do it (Since JDK 1.5 there is this thing called covariant return types, where something like this is possible).
abstract class SuperClass<T extends SuperClass<T>>{
public abstract T getSelf();
}
class SubClass extends SuperClass<SubClass> {
public SubClass getSelf() { return this; }
}
public class Generics {
public static void main(String[] args) {
System.out.println(new SubClass().getSelf());
}
}
Notice a similar class generic definition with Enum (http://download.oracle.com/javase/1,5.0/docs/api/java/lang/Enum.html)
See what happens behind the scenes (by using javap SuperClass SubClass):
class SubClass extends SuperClass{
SubClass();
public SubClass getSelf();
public SuperClass getSelf();
}
abstract class SuperClass extends java.lang.Object{
SuperClass();
public abstract SuperClass getSelf();
}
Notice how the subclass method has a different return type, which is a subtype of the super method return type.
Btw, notice that public SuperClass getSelf(); in class SubClass is actually a synthetic method.