0

I have a class heirarchies defined as follows:

class ClassA{}

class ClassB extends ClassA{}

class BaseClass
{
    public <T extends ClassA> T method1(){ return null; }

    public <T extends ClassA> T method2(T param1){ return null; }
}

I want to extend the above BaseClass and override the implementations of method1 and method2, but I'm struggling with the method signature in the DerivedClass. Here's what I tried:

class DerivedClass extends BaseClass
{
    @Override
    public ClassB method1() {return new ClassB();}

    @Override
    public ClassB method2(ClassB param1) {return new ClassB();}
}

For method1, I get the warning:

Type safety: The return type ClassB for method1() from the type DerivedClass needs unchecked conversion to conform to T from the type BaseClass

For method2, I get the following error:

The method method2(ClassB) of type DerivedClass must override or implement a supertype method

How do I resolve this?

Edit: I had to refactor the design and put the generic type on the BaseClass instead of each individual methods, so that such scenario doesn't occur.

JavaLearner
  • 527
  • 1
  • 5
  • 16
  • It seems like both of the answers address your question about the errors you are getting and how you can resolve them. You should edit the question to include more context so we can see why these answers don't suite your situation. – matt Aug 27 '21 at 09:32

2 Answers2

0

This method will works.

public class BaseClass<T extends ClassA> {
    public T method1() {
        return null;
    }

    public T method2(T param1) {
        return null;
    }
}
public class DerivedClass extends BaseClass<ClassB> {
    @Override
    public ClassB method1() {
        return new ClassB();
    }

    @Override
    public ClassB method2(ClassB param1) {
        return new ClassB();
    }
}
ZIHAO LIU
  • 402
  • 2
  • 8
  • 3
    You're not wrong: this will work. But this doesn't explain at all what's different or why this would be better. – Joachim Sauer Aug 27 '21 at 08:24
  • Yes, I understand that but in order to have a single instance of BaseClass, I had applied the generic parameters on methods. If I instead put the generic parameter on base class then I would need to create separate instance for each type. The main motive is to avoid creating these separate instances for each type. – JavaLearner Aug 27 '21 at 09:01
0

The first warning is because JVM, due to type erasure cannot know whether the ClassB is proper (does it extend ClassA) and because there is a risk that some exception will be throw it warns you. To fix this you can add SuppressWarnings annotation over the method

@Override
@SuppressWarnings("unchecked")
public ClassB method1() {return new ClassB();}

The second thing is quite similar but now JVM cannot create proper type/method signature (please notice that return type is not included into signature in Java! Please also notice that public ClassA method2(ClassA param1) method would not cause such error).

To solve this you need to make compiler sure that the overridden method will have proper signature and to do this you need to move the generic type declaration on the class level

class BaseClass <T extends ClassA> 

then extend this class with proper type

class DerivedClass extends BaseClass<ClassB> {
    @Override
    public ClassB method1() { // notice that you don't need Suppress annotation anymore
        return new ClassB();
    }

    @Override
    public ClassB method2(ClassB param1) {
        return new ClassB();
    }
}

Now the compiler is able to check whether used type is in bound or not

class ClassC {}
class DerivedClass extends BaseClass<ClassC> {
// ERROR: Type parameter 'com.mantkowicz.example.ClassC' is not within its bound

Read more here:

m.antkowicz
  • 13,268
  • 18
  • 37
  • In order to have a single instance of BaseClass, I had applied the generic parameters on methods. If I instead put the generic parameter on base class then I would need to create separate instance for each type. The main motive is to avoid creating these separate instances for each type. – JavaLearner Aug 27 '21 at 08:59
  • @JavaLearner can you illustrate that problem? It's not really clear why you need generics at all. You could just return as a ClassA. Then both of your methods work. – matt Aug 27 '21 at 09:08
  • @JavaLearner then just create a `public ClassB method2(ClassB param1)` without `@Override` and, if necessary, call super method like e.g. `return (ClassB) super.method2(param1);`. What you are currently trying to do is not proper usage of inheritance and Java compiler won't you let to do it this way – m.antkowicz Aug 27 '21 at 09:11
  • @matt I have a method with signature `void callMethods(BaseClass b);` outside of all these classes. All it does is calls `methodA` and `methodB` on it's param `b`. For most cases I just want to use `BaseClass` but for some cases I want to override it and use `DerivedClass`. There can be multiple such DerivedClasses. If I go ahead with making BaseClass accept a generic parameter, then each call to `callMethods` would require creating a separate `BaseClass` object with a given type attached to it, which I want to avoid. – JavaLearner Aug 27 '21 at 09:26
  • "...would require creating a separate BaseClass object with a given type attached to it," Isn't that exactly what you're doing? "...but for some cases I want to override it and use DerivedClass" Isn't derived class going to be a separate instance? – matt Aug 27 '21 at 09:29
  • `Isn't that exactly what you're doing?` Nope, the BaseClass currently does not accept any generic parameter, so I can use it for multiple different types. `Isn't derived class going to be a separate instance?` Yes – JavaLearner Aug 27 '21 at 09:32