Programmati c тип возврата или приведение для получения и вызова методов потомка с родителем c - PullRequest
0 голосов
/ 10 января 2020

-Классы проекта-

Класс A:

public class A {
    public static void main(String[] args) {
        D d = new D();
        B.set(d);

        d.add(new H()); //$ (correct error)
        B.get().add(new H()); //! (no error)
    }
}

Класс B:

public class B {
    protected static C c;

    public static C get() {
        return B.c;
    }

    public static void set(C c)
        B.c = c;
}

Класс C:

public abstract class C<T> {
    protected ArrayList<T> array = new ArrayList<T>();

    public void add(T element) {
        this.array.add(element);
    }
}

Класс D:

public class D extends C<G> {
    //
}

Класс E:

public class E extends C<H> {
    //
}

Класс F:

public abstract class F<T> {
    //
}

Класс G:

public class G extends F<X> {
    //
}

Класс H:

public class H extends F<Y> {
    //
}

- класс ролей-

  1. A - это основной класс
  2. B - это класс, в котором хранится ссылка на объект
  3. C - это обобщенный c класс, который определяет массив объектов
  4. D & E extension C с различными типами
  5. G & H расширение F с различными типами

-Logi c Issue-

В A.main(), //! представляет, где находится проблема, и //$ представляет желаемое поведение. Поскольку B.get() возвращает абстрактный тип C, можно добавить недопустимый элемент в array (в этом примере добавление H, когда только G допустимо из-за расширения D C).

Тип возвращаемого объекта из B.get() неизвестен в программе (поскольку B.c может представлять объект типа D или типа E), поэтому идеально подходит модификация B для проверки типа c и его возврата или автоматического приведения при вызове B.get(), если это возможно.

-Вопросы редактирования-

Для уточнение, приведение с ((D) B.get()).add(new H()); бесполезно, так как дочерний тип, который содержит B. c, неизвестен. Если возможно сделать что-то похожее на ((B.get().getClass()) B.get()).add(new H()), это было бы полезно. Решение, которое я выбрал бы, было бы предпочтительно изменением или в методе B.get(), а не в основном методе, если это возможно.

Для дальнейшего разъяснения, результат решения этой проблемы предполагается приводить к ошибке , чтобы предотвратить нежелательное добавление недопустимых типов в массивы при ссылке из B.get() (//! обозначает, где не возникает ошибка, а //$ обозначает, где возникает ошибка , как и должно быть ). Я открыт для переписывания того, как сохранять ссылки на экземпляры D и E в B, если можно сделать динамический c способ ссылки на тип C (тип D или введите E) можно сделать.

1 Ответ

0 голосов
/ 10 января 2020

Generi c типы работают только во время компиляции. Похоже, вы пытаетесь заставить дженерики делать динамическую безопасность типов, что они ужасно делают из-за стирания. Использование B в качестве синглтона, чье состояние c c имеет постоянно меняющийся тип, невероятно неудобно. Вы могли бы попытаться сохранить отображение от Class<?> до C<?> в B и получить соответствующее, прежде чем пытаться вызвать add, я полагаю.

Кроме того, на //$ вы просто использовали неправильный подкласс.

d.add(new G());

проверки типов правильно.

Вот что я имел в виду:

public class A {
    public static void main(String[] args) {
        D d = new D();
        B.put( G.class, d);
        B.get( H.class ).add(new H()); // dynamic typing, but susceptible to null as written
        d.add(new G()); //$ (no longer causes error)
    }
}

public class B {
    protected static Map< Class<?>, C<?> > mapC;

    public static <T> C<T> get( Class<T> clsT ) {
        return ( C< T > )mapC.get( clsT );
    }

    public static < T > void put(Class< T > clsT, C<T> c) {
        mapC.put( clsT, c );
    }
}

public abstract class C<Type> {
    protected ArrayList<Type> array = new ArrayList<Type>();

    public void add(Type element) {
        this.array.add(element);
    }
}

public class D extends C<G> {
    //
}

public class E extends C<H> {
    //
}

public abstract class F<Type> {
    //
}

public class G extends F<String> {
    //
}


public class H extends F<Integer> {
    //
}
...