Это что-то такое на яве?

#java #class #oop #return #game-engine

Вопрос:

Поэтому я хочу иметь функцию для своего игрового движка, которую я пишу на java, где она будет возвращать объект типа T . Мой код для этой функции выглядит так:

 public <T> T getComponent(Class<T> tClass)
    {
        for(Component component : components)
        {
            if(component.getClass() == tClass)
            {
                return(T)component;
            }
        }
        return(null);
    }
 

И это хорошо работает, и я могу назвать это с
getComponent(Component.class);
Однако я хочу иметь возможность называть это так, как я бы назвал это с помощью C# ( getComponent<Component>(); ), поэтому мне интересно, возможно ли это.

Сказать мне, возможно это или нет, было бы здорово, и дать мне код для его реализации было бы еще лучше, спасибо вам за любой ваш вклад, даже если вы просто читаете это, чтобы больше людей увидели это.

Комментарии:

1. Я не верю, что это возможно.

2. На английском языке, чего вы на самом деле пытаетесь достичь?

3. Это невозможно. Дженерики Java были реализованы с удалением типов в качестве дополнения к существующему языку с нулевой стоимостью. Тебе нужно tClass делать то, что ты делаешь.

4. Плохое название. Перепишите, чтобы обобщить вашу конкретную техническую проблему.

Ответ №1:

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

Ответ №2:

Поэтому я подумал, что, возможно, использования свидетеля типа в сочетании с ловлей ClassCastException может быть достаточно, чтобы сделать трюк здесь. К сожалению, даже в этом случае стирание сделает невозможным (без Class<T> этого метода):

 public class Test {

    private static final List<? extends Entity> entities = new ArrayList<>(Arrays.asList(
                                            new A(), new B(), new C(), new B()));
    
    public static void main(String... args) {
        B next = Test.<B>getMatchingEntity(); //Class-cast exception here
    }

    //Always returns <Test$A>
    private static <T extends Entity> T getMatchingEntity() { //<T> == Test$B
        for (Entity e : Test.entities) {
            T back;
            try {
                back = (T) e; //Assigns Test$A here
            } catch (ClassCastException badPractice) {
                continue; //never thrown! erases to <Test$Entity> instead of <Test$B>
            }
            return back; //returns first result regardless
        }
        return null;
    }

    public static class Entity {}
    public static class A extends Entity {}
    public static class B extends Entity {}
    public static class C extends Entity {}
}
 

Комментарии:

1. Это слишком сложно. Я думаю, что просто обойдусь без

2. Это в основном просто доказательство (через исчерпание) того, что это невозможно, ваш подход Class<T> разумен и верен.

3. О, я не мог этого понять, поэтому подумал, что это сработало.

Ответ №3:

Нет, то, чего вы пытаетесь достичь, невозможно, и я могу объяснить почему.

В отличие от универсальных программ C#, универсальные программы Java являются функцией времени компиляции. Это в основном означает, что после компиляции кода Java не известно никакой информации о фактическом типе универсального аргумента. Это называется стиранием типа, потому что тип универсального аргумента теряется или стирается после времени компиляции, и это означает, что, хотя технически вы могли бы объявить подобный метод в Java:

 public <T> T getComponent() { ... }
 

И технически вы могли бы вызвать этот метод следующим образом (как в C#).:

 getComponent<YourType>();
 

На самом деле вы не сможете получить тип T внутри метода, потому что эта информация не существует во время выполнения, и поэтому написание такого метода было бы довольно бесполезным. Чтобы сохранить фактический тип T во время выполнения, вам нужно либо передать методу объект типа T , либо передать Class<T> объект в качестве параметра, что вы и сделали в своем коде.

Разница здесь в конечном счете сводится к тому, как разработчики Java и C# решили реализовать универсальные языки на своем языке. Здесь есть отличное сравнение между C# и Java-генераторами, которое я настоятельно рекомендую проверить, если вы хотите узнать больше.

Я сделаю только один комментарий к предоставленному вами коду. Вы готовите непроверенный бросок на этой линии:

 return (T)component;
 

Но, поскольку вы передаете объект этого типа Class<T> в качестве параметра, вместо этого вы можете выполнить приведение следующим образом:

 return tClass.cast(component);
 

Таким образом, вы можете избавиться от непроверенного предупреждения о приведении, которое вы, вероятно, получаете от компилятора.