#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);
Таким образом, вы можете избавиться от непроверенного предупреждения о приведении, которое вы, вероятно, получаете от компилятора.