Как общий базовый тип может быть приведен с помощью отражения в Java?

1

Скажем, у меня есть следующий класс:

public class MyClass<T> {
    Class<T> type;
    List<T> items;
    public Class<T> getType() { return type; }
    ...
}

Мне нужно хранить объекты вышеуказанного класса в общем контейнере:

public class MyContainer<T> {
    Class<T> type;
    List<MyClass<T>> myClasses;
    public Class<T> getType() { return type; }
    ...
}

Скажем позже в моем коде, мне предоставляется общий объект в качестве аргумента:

public class Main {
    public static void main() {
        List<MyContainer<?>> containers;
        ...
    }
    public void someMethod(MyClass<?> myClass){
        ...
    }
}

У меня тип T как отражение. Мне нужно вернуть MyClass<?> Обратно к его предполагаемому типу. Поэтому, если он был объявлен как MyClass<String> мне нужно вернуть его в MyClass<String>. Я не могу сделать этого с типом отражения, потому что он способен только набрасывать T, а не MyClass<T>.

Я мог бы бросить T, сделав это, например:

myClass.getType().cast(myClass.getItem()); // Where getItem returns an object of the type T

Но я хочу, чтобы это:

myClass.getType().cast(myClass); // getType() returns T not MyClass<T>

Итак, вопрос в том, как я применил общий базовый тип вместе с его типом отражения, учитывая приведенный выше сценарий?

  • 0
    зачем вам это? Универсальный тип T не существует во время выполнения (когда происходит отражение), поэтому я не совсем понимаю, что вы пытаетесь сделать.
  • 0
    У меня есть список контейнеров, который содержит список объектов, который содержит список объектов. В этом случае: у объекта Container есть список объектов MyClass, а у объекта MyClass есть список T объектов. Таким образом, это список в списке внутри списка типизированного контейнера. Контейнер должен быть универсальным, потому что мне нужен контейнер, чтобы он мог содержать любой тип объекта. Во втором слое - в MyClass, мне нужно по-разному управлять объектом в зависимости от типа. Например, если это MyClass <Person>, я хочу отобразить таблицу с 10 столбцами. Или, если это MyClass <Tree>, я могу отображать только 5 столбцов
Показать ещё 1 комментарий
Теги:
reflection

2 ответа

0
Лучший ответ

Это невозможно из-за стирания типа. Отражение не может помочь вам здесь, потому что во время выполнения общая информация типа недоступна. Другими словами, во время выполнения нет MyClass<String>, есть только MyClass. MyClass<String> - это чистая компиляция.

Если у вас есть часть кода, ожидающая определенного типа, объявите это во время компиляции. Ожидание этого типа может быть конкретным или общим:

public void someMethod(MyClass<String> myClass)

или

public <T> void someMethod(MyClass<T> myClass)

Если вы знаете тип, вам не нужен cast(), вы можете просто нажать:

@SuppressWarnings("unchecked")
MyClass<String> myClassStr = (MyClass<String>)expression;
  • 0
    спасибо, я думаю, что я мог бы пойти с вещью @SuppressWarnings
  • 0
    Код будет компилироваться даже без предупреждения. Рекомендуется компилировать кодовую базу без предупреждений. Еще лучше избегать причины предупреждения, если это возможно. (Если ответ решит вашу проблему, пожалуйста, примите его :-))
0

Поскольку T не существует во время выполнения, что вы знаете, вы не можете его использовать. Вы также не можете получить Class<List<T>>.

myClass.getType().cast(myClass.getItem()) действительно не работает для вас, потому что если у вас есть MyClass<?> то у вас также есть Class<?> который возвращает объект. Class<T> тоже не поможет, потому что вам действительно нужно знать, что такое T

Вы можете в значительной степени сделать две вещи.

Использовать решения:

if(myClass.getType() == String.class) {
    @SuppressWarnings("unchecked")
    final MyClass<String> myStrings = (MyClass<String>)myClass;

    // use MyClass<String> ...
}

Использовать полиморфизм:

MyClass<String> myClass = new MyClass<String>(...,
        new BiConsumer<String, JTable>() { // (or lambda ...)
    @Override
    public void accept(String s, JTable table) {
        // use String ...
        // configure JTable ...
    }
});

... elsewhere ...

public void someMethod(MyClass<?> myClass) {
    someCaptureMethod(myClass);
}

private <T> void someCaptureMethod(MyClass<T> myClass) {
    Consumer<T, JTable> consumer = myClass.getConsumer();

    for(T theT : myClass.getList()) {
        consumer.accept(theT, myTable);
    }
}

Как правило, второй пример считается "лучшим", но код может быть длиннее в версиях Java до 8.

  • 0
    Почему второй считается лучше? Кажется, что компонент создания и управления тесно связан в начале кода. И довольно громоздко, если вам нужно переписать код конфигурации для каждого экземпляра MyClass. А что если вы захотите выпустить свой код, чтобы другие могли просто «создавать» объекты MyClass и оставлять аспект конфигурации в «черном ящике»?
  • 0
    Это ООП способ делать подобные вещи . Если вам это не нравится, вы можете поместить функциональный объект в другое место, например, в Map. Или не используйте это. Решение и состав могут быть проще, если у вас есть только несколько видов T Главное, на что я отвечаю - это два варианта.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню