Ограничить параметр ограниченного типа A <B>и A <C> - PullRequest
0 голосов
/ 06 мая 2020

Я хочу привязать параметр типа дочерних классов. Предположим, это классы:

class A {}
class B extends A {}
class C extends A {}

Я хочу привязать указанные выше классы, чтобы кто-то, создающий класс, мог передать только собственное имя класса. Например:

class B extends A<B> {} // valid
class C extends A<B> {} // invalid
class C extends A<C> {} // valid

Ближайшее, что я мог найти, это:

class A<T extends A<? super T>> {}
class B extends A<B> {}
class C extends A<B> {} // allows it, but I don't want to allow this.

Как этого можно достичь?

Пример использования:

class A<T extends A<? super T>> {
    private T t;
    private A() {}
    protected A(T t) {this.t = t;}
    public T something() { return t; }
}
class B extends A<B> {
    public B(B b) {super(b);}
    public B anotherthing() { return this.something(); }
}

1 Ответ

0 голосов
/ 06 мая 2020

Невозможно сделать это во время компиляции.

Если вы действительно хотите, вы можете принудительно применить его во время выполнения (предотвращая создание экземпляров классов c), добавив logi c в неперсональный конструктор A:

    protected A(T t) {
        validateClass(getClass());
        this.t = t;
    }

    private static void validateClass(final Class<?> clazz) {
        final Type superclass = clazz.getGenericSuperclass();
        if ((superclass instanceof ParameterizedType)
            && ((ParameterizedType)superclass).getRawType() == A.class
            && ((ParameterizedType)superclass)getActualTypeArguments()[0] == clazz
        ) {
            // OK
        } else {
            throw new IllegalStateException(
                clazz + " does not extend A<" + class.getName() + ">");
        }
    }

. . . но я не думаю, что это отличная идея.

В целом, хотя Java предоставляет множество функций для защиты во время компиляции, программа Java в конечном итоге полагается на разработчиков, которые добровольно пишут правильный код. Многие аспекты контрактов классов задокументированы, но не применяются. (Например, ничто не заставляет методы hashCode() и equals() согласовываться друг с другом; но если вы пишете код Java, вы прочтете документацию по этим методам, прежде чем переопределить их, чтобы знать, что вам нужно это сделать.) В вашем случае вам лучше просто сказать разработчикам, что подклассы A должны передавать себя в качестве аргумента типа A, дав им пример и доверив им это сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...