这是 java 中的事情吗?
Is this a thing in java?
所以我想为我在 java 中编写的游戏引擎提供一个函数,它将 return 类型为 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>();
) 那样调用它,所以我想知道这是否可行。
告诉我它是否可能会很棒,如果给我代码来实现它会更好,感谢您所做的任何贡献,即使它只是为了让更多人看到它而阅读它。
根据评论似乎认为这是不可能的,所以现在关闭了。
所以我想也许结合使用类型见证和捕获 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 {}
}
不,你想要达到的目标是不可能的,我可以解释原因。
与 C# 泛型不同,Java 泛型是 编译时 特性。这基本上意味着,在编译 Java 代码之后,没有关于泛型参数实际类型的信息。这称为 type erasure,因为泛型参数的类型在编译时间后丢失或擦除,这意味着虽然您可以 技术上 在 Java:
中声明这样的方法
public <T> T getComponent() { ... }
并且您可以技术上像这样调用该方法(就像在 C# 中一样):
getComponent<YourType>();
您实际上无法在方法中获取 T
的类型,因为该信息在运行时不存在,因此编写这样的方法将毫无用处。为了在运行时保留 T
的实际类型,您需要将类型 T
的对象传递给方法,或者将 Class<T>
对象作为参数传递,这就是你在你的代码中做了。
这里的区别最终归结为 Java 和 C# 的开发人员如何选择在他们的语言中实现泛型。 C# 和 Java 泛型 here 之间有一个很好的比较,如果您想了解更多,我强烈建议您查看。
我只会对您提供的代码发表评论。您正在这条线上进行未经检查的转换:
return (T)component;
但是,由于您将 Class<T>
类型的对象作为参数传递,因此您可以这样转换:
return tClass.cast(component);
这样你就可以摆脱你可能从编译器那里得到的未经检查的转换警告。
所以我想为我在 java 中编写的游戏引擎提供一个函数,它将 return 类型为 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>();
) 那样调用它,所以我想知道这是否可行。
告诉我它是否可能会很棒,如果给我代码来实现它会更好,感谢您所做的任何贡献,即使它只是为了让更多人看到它而阅读它。
根据评论似乎认为这是不可能的,所以现在关闭了。
所以我想也许结合使用类型见证和捕获 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 {}
}
不,你想要达到的目标是不可能的,我可以解释原因。
与 C# 泛型不同,Java 泛型是 编译时 特性。这基本上意味着,在编译 Java 代码之后,没有关于泛型参数实际类型的信息。这称为 type erasure,因为泛型参数的类型在编译时间后丢失或擦除,这意味着虽然您可以 技术上 在 Java:
中声明这样的方法public <T> T getComponent() { ... }
并且您可以技术上像这样调用该方法(就像在 C# 中一样):
getComponent<YourType>();
您实际上无法在方法中获取 T
的类型,因为该信息在运行时不存在,因此编写这样的方法将毫无用处。为了在运行时保留 T
的实际类型,您需要将类型 T
的对象传递给方法,或者将 Class<T>
对象作为参数传递,这就是你在你的代码中做了。
这里的区别最终归结为 Java 和 C# 的开发人员如何选择在他们的语言中实现泛型。 C# 和 Java 泛型 here 之间有一个很好的比较,如果您想了解更多,我强烈建议您查看。
我只会对您提供的代码发表评论。您正在这条线上进行未经检查的转换:
return (T)component;
但是,由于您将 Class<T>
类型的对象作为参数传递,因此您可以这样转换:
return tClass.cast(component);
这样你就可以摆脱你可能从编译器那里得到的未经检查的转换警告。