Why does the interface extension not allow the method to return more accurate types?

For example, if we have a class Person, and the class Studentextends Person. We may have:

public interface PersonQueryBuilder<T extends Person> {
    PersonQueryBuilder<T> withName(String name);

    PersonQueryBuilder<T> withAgeBetween(int from, int to);

    List<T> getResultList();
}

public interface StudentRepository<T extends Student> extends PersonQueryBuilder<T> {
    StudentRepository studying(Course course);
}

So why, when I have StudentRepository, the withName () and withAgeBetween () methods return PersonQueryBuilder and not and StudentRepository? This is very annoying. Is there an โ€œelegantโ€ way to solve this problem?

+3
source share
3 answers

This is ridiculous. I suggest the following (ugly?) Solution that does not require you to redefine the methods in the interface as Mark's answer:

interface PersonQueryBuilder<T extends Person, U extends PersonQueryBuilder<T,U>> {
    U withName(String name);

    U withAgeBetween(int from, int to);
}

interface StudentRepository extends PersonQueryBuilder<Student, StudentRepository> {
    StudentRepository studying(Course course);
}

You also use source types as results in your current implementations of your methods with.

+3
source
interface StudentRepository<T extends Student> extends PersonQueryBuilder<T> {
   StudentRepository<T> studying(Course course);
   StudentRepository<T> withName(String name);
   StudentRepository<T> withAgeBetween(int from, int to);
}

-. StudentRepository StudentRepository , - PersonQueryBuilder.

+4

-, raw Type PersonQueryBuilder . T , T? , :

PersonQueryBuilder<T> withName(String name);

PersonQueryBuilder<T> withAgeBetween(int from, int to);

, StudentRepository PersonQueryBuilder , :

interface UniversityRepository<T extends Student> extends PersonQueryBuilder<T> { }

, , StudentRepository UniversityRepository? - ? , , , , :

public interface StudentRepository<T extends Student> extends PersonQueryBuilder<T> {
    @Override
    StudentRepository<T> withName(String name);

    @Override
    StudentRepository<T> withAgeBetween(int from, int to);

    StudentRepository<T> studying(Course course);
}

The obvious drawback of this approach is that you need to repeat all the inherited methods. You can get around this with the type parameter for the real repository:

public interface PersonQueryBuilder<T extends Person, R extends PersonQueryBuilder<T, R>> {
    R withName(String name);

    R withAgeBetween(int from, int to);

    List<T> getResultList();
}

and

public interface StudentRepository<T extends Student, R extends StudentRepository<T, R> extends PersonQueryBuilder<T, R> {
    R studying(Course course);
}
+2
source

All Articles