Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics incompatible types while subclassing

Tags:

java

generics

While sub classing from generic class type/Formal type parameter T/E with valid class type/Actual type parameter say e.g. Type/String there are many combinations occurs and that confusing which one to use and when?

    public class SubClass<T> implements SuperIfc<T>  <-- It is straight forward to understand
    public class SubClass<T> implements SuperIfc<Type>

    public class SubClass<Type> implements SuperIfc<T>
    public class SubClass<Type> implements SuperIfc<Type>
    public class SubClass<Type> implements SuperIfc
    public class SubClass implements SuperIfc<Type>
    public class SubClass implements SuperIfc<T>    <--- Hope we cannot declare <T> in his case while initialising SubClass.

    // Bounded type parameter
    public class SubClass<T extends Type> implements SuperIfc<Type>
    public class SubClass<T extends Type> implements SuperIfc<T> <-- Looks <T> at SuperIfc also refers <T extends Type>, and no need to declare it again at SuperIfc.

    // Recursive type bound
    public class SubClass<T extends Comparable<T>>> implements SuperIfc<T>
    public class SubClass<T extends Comparable<T>>> implements SuperIfc<Type>

So that i can be more clearer on solving incompatible types while subclassing

Case_1:

public class Test {

    interface TestIfc {

        public static <T extends TestIfc> T of(int choice) {

            if(choice == 1) {
                return new TestImpl(); <-- PROB_1: incompatible type error 
            } else {
                return new SomeOtherTestImpl(); //incompatible type error
            }
        }
    }

    static class TestImpl implements TestIfc {}
    
    static class SomeOtherTestImpl<T extends TestIfc> implements TestIfc {

        //The below method also having same error though with declaration
        public T of() {
            return new TestImpl();  <-- PROB_2: incompatible type error
        }
    }
}

Case_1: PROB_1: return type is T extends TestIfc and returned TestImpl implements TestIf So what is wrong?

Case_1: PROB_2: Similar to PROB_1, how to rectify without external casting. Please help.


Case_2:

public interface SuperIfc<T> {
    
    public T create(Object label);
}

class Type {

    public static Type of(){
         return new Type();
    }
}
------

public class SubClass<Type> implements SuperIfc<Type>{

    @Override
    public Type create() {
        return Type.of(); <---- PROB_1: cannot resolve method
    }
}
-------

public class SubClass<T extends Type> implements SuperIfc<Type>{

    @Override
    public Type create() {
        return Type.of(); <---- PROB_1: is resolved
    }
}

SuperIfc<Type> object = new SubClass(); <-- PROB_2 Unchecked assignement warning
SuperIfc<Type> object = new SubClass<TypeImpl>(); <-- PROB_3: bound should extend Type
  1. I would like to know how to resolve Case_2, PROB_1 and PROB_2 together?

  2. How to write subclass for generic super class with class types and what are the rules?

  3. What should be taken care when changing generic T to class Type while subclassing? may be the difference between below and when to use?

     public class SubClass<Type> implements SuperIfc<Type>
     public class SubClass<Type> implements SuperIfc
     public class SubClass implements SuperIfc<Type>
     public class SubClass<T extends Type> implements SuperIfc<Type>
     public class SubClass<T extends Type> implements SuperIfc<T>
     public class SubClass<T> implements SuperIfc<Type>
    
like image 982
Kanagavelu Sugumar Avatar asked May 14 '20 04:05

Kanagavelu Sugumar


2 Answers

In the first of() method, the method can return any type that implements InformationIfc, but your method always returns a specific implementation - InformationImpl - which is not acceptable.

For example, if you had some other class SomeOtherInformationImpl that implements that interface, the caller of that method would be allowed to write:

SomeOtherInformationImpl i = InformationImpl.of();

but your method doesn't return a SomeOtherInformationImpl.

The second of() method has the same issue as the first method. If you instantiated your class with:

InformationImpl i = new InformationImpl<SomeOtherInformationImpl>();

the of() method would have to return a SomeOtherInformationImpl, not a InformationImpl.

like image 110
Eran Avatar answered Sep 29 '22 14:09

Eran


Problems with case one.

PROB_1: return type is T extends TestIfc

Why do you have a generic here at all?. Since you have a static method I can do.

TestIfc broken = TestIfc<SomeOtherImplementation>.of(0);

SomeOtherImplementation is not a TestImpl. This is broken by design. What you really want is.

 public static TestIfc of(int choice)

Next.

static class SomeOtherTestImpl<T extends TestIfc> implements TestIfc {

TestIfc is not parameterized, SomeOtherTestImp is, but it is completely unrelated to the interface you're implementing. Not to mention, TestIfc has a static method of that has nothing to do with the interface.

If I had to guess, I would think you want.

interface TestIfc<T>{}
static class TestImpl implements TestIfc<TestImpl> {}
static class SomeOtherTestImpl<T extends TestIfc> implements TestIfc<T>{}

That is the best I could come up with, because it is unclear what you actually want to happen.

Your examples for question 3

public class SubClass<Type> implements SuperIfc<Type>

This is broken, because SubClass<Type> declares Type to be the name of a generic parameter. It puts no restriction on the type, hence you get the method not found error.

public class SubClass<Type> implements SuperIfc

Broken, makes a generic parameter named Type, has nothing to do with your raw type version of SuperIfc

public SubClass implements SuperIfc<Type>

This is good.

public class SubClass<T extends Type> implements SuperIfc<Type>
public class SubClass<T> implements SuperIfc<Type>

These are both good, but the T has no relation to the SuperIfc parameter, hence your implementation would be.

public Type create(Object label);

The first generic parameter says the name you're going to use through the class.

like image 27
matt Avatar answered Sep 29 '22 14:09

matt