I've tried to condense this issue down to the smallest amount of code that I could.
I have defined a table structure, like a database table, with the Row and Table classes below.  A Table is essentially a list of Row.  I want subclasses to define their particular flavor of Table and Row and I want the compiler to catch inappropriate attempts to put rows of one type into tables of an incompatible type.
The abstract Agent class provides a method to take parameters and return a table that takes rows of type T.  I have defined three methods to illustrate the problem that I am having.
The FinalAgent, FinalTable, and FinalRow classes define implementations of the Agent, Table, and Row classes.  Ultimately, what I want is method2a, which takes a list of parameters and returns a table of type FinalTable.
public abstract class Row {}
public abstract class Table<T extends Row> {}
public abstract class Agent {
    public <T extends Row> Table<T> method1(List<String> parameter) {
        return null;
    }
    public <T extends Row> Table<T> method2a(List<String> parameter) {
        return null;
    }
    public <T extends Row> Table<T> method2b(String parameter) {
        return null;
    }
}
public class FinalRow extends Row {}
public class FinalTable extends Table<FinalRow> {}
public class FinalAgent extends Agent {
    @Override
    public <T extends Row> Table<T> method1(List<String> parameter) {
        return null;
    }
    @Override
    public FinalTable method2a(List<String> parameter) {
        return null;
    }
    @Override
    public FinalTable method2b(String parameter) {
        return null;
    }
}
At the bottom:
method1 of FinalAgent compiles, but I have to write Table<FinalRow> t1 = new FinalAgent().method1(null); in order to call the method.method2a of FinalAgent I changed the return type to FinalTable to reflect what I am actually returning (I want to write FinalTable t2a = new FinalAgent().method2a(null);), but the compiler produces the error: The method method2a(List) of type FinalAgent must override or implement a supertype method
method3 I changed the parameter from a List to a String.  The method compiles OK but gives me a type safety warning, which I can at least work with.So, finally, the question: Is it a compiler bug that method2a in FinalAgent does not compile yet method2b does compile?
I might as well also ask, is there a better way to do what I am doing?
Core Java bootcamp program with Hands on practiceA type parameter can have multiple bounds.
Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.
A type parameter, also known as a type variable, is an identifier that specifies a generic type name. The type parameters can be used to declare the return type and act as placeholders for the types of the arguments passed to the generic method, which are known as actual type arguments.
Multiple parameters You can also use more than one type parameter in generics in Java, you just need to pass specify another type parameter in the angle brackets separated by comma.
It's not clear why you're parameterizing the methods. You're promising to return a Table<T>, but your method can't identify T at runtime because of type erasure. You probably want to parameterize the entire Agent class instead:
public abstract class Agent<T extends Table<?>> {
    public T method1(List<String> parameter) {
        return null;
    }
    public T method2a(List<String> parameter) {
        return null;
    }
    public T method2b(String parameter) {
        return null;
    }
}
public class FinalAgent extends Agent<FinalTable> {
    @Override
    public FinalTable method1(List<String> parameter) {
        return null;
    }
    @Override
    public FinalTable method2a(List<String> parameter) {
        return null;
    }
    @Override
    public FinalTable method2b(String parameter) {
        return null;
    }
}
As for your initial question, I can't make sense of the discrepancy or the warning message on method2b.
Using a method parameter at a single place means the parameter is usually unnecessary
With methods like that in Agent, FinalAgent compiles fine:
public Table<? extends Row> method2a(List<String> parameter) {
    return null;
}
public Table<? extends Row>  method2b(String parameter) {
    return null;
}
                        This is direct consequence of raw type.
method1 is still a generic method : no issue.method2b is not anymore a generic method but override the method in  Agent : no issue (except the safety warning though, due to the unchecked conversion)method2a is not anymore a generic method but does not override anything
method2a is seen declared like this from FinalAgent, after compilation : 
public Table method2a(List parameter) 
But defined like this in FinalAgent :
public FinalTable method2a(List<String> parameter)
And now you are stuck. Same erasure but does not override correctly method2a
Here is a simple example :
public interface Foo
{
    public void bar(List a);
}
public class FooChild implements Foo
{
    @Override
    public void bar(List<String> a)
    {
    }
}
It gives The method bar(List<String>) of type FooChild must override or implement a supertype method
public interface Foo
{
    public void bar(List a);
}
public class FooChild implements Foo
{
    public void bar(List<String> a)
    {
    }
}
It gives Name clash: The method bar(List<String>) of type FooChild has the same erasure as bar(List) of type Foo but does not override it
Another example. This code compiles fine :
public interface Foo
{
    public void bar(List<String> a);
}
public class FooChild implements Foo
{
    public void bar(List<String> a)
    {   
    }   
}
This one does not :
public interface Foo
{
    public <T> void bar(List<String> a);
}
public class FooChild implements Foo
{
    public void bar(List<String> a)
    {   
    }   
}
It gives Name clash: The method bar(List<String>) of type FooChild has the same erasure as bar(List<String>) of type Foo but does not override it
As soon as bar becomes a generic method, it is seen with raw types and we can notice the same issue.
A different example of raw type issue : Name clash when overriding method of generic class
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With