这是 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);

这样你就可以摆脱你可能从编译器那里得到的未经检查的转换警告。