【问题标题】:Is this a thing in java?这是java中的东西吗?
【发布时间】:2021-06-04 15:49:02
【问题描述】:

所以我想为我用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&lt;Component&gt;();) 一样调用它,所以我想知道这是否可能。

告诉我它是否可能会很棒,并给我代码来实现它会更好,感谢您所做的任何贡献,即使它只是阅读本文以便更多人看到它。

【问题讨论】:

  • 我不相信这是可能的。
  • 用英语,你到底想达到什么目的?
  • 不可能。 Java 泛型是通过类型擦除实现的,作为对现有语言的 0 成本附加。你需要tClass 来做你正在做的事情。
  • 糟糕的标题。重写以总结您的具体技术问题。

标签: java class oop return game-engine


【解决方案1】:

不,你想要达到的目标是不可能的,我可以解释原因。

与 C# 泛型不同,Java 泛型是一种编译时 特性。这基本上意味着,在编译 Java 代码之后,没有关于泛型参数的实际类型的信息。这称为类型擦除,因为泛型参数的类型在编译后会丢失或擦除,这意味着虽然您可以技术上声明这样的方法在 Java 中:

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

您可以技术上像这样调用该方法(就像在 C# 中一样):

getComponent<YourType>();

您实际上无法在方法中获取T 的类型,因为该信息在运行时不存在,因此编写这样的方法将毫无用处。为了在运行时保留T 的实际类型,您需要将T 类型的对象传递给该方法,或者将Class&lt;T&gt; 对象作为参数传递,这就是您在代码中所做的。

这里的区别最终归结为 Java 和 C# 的开发人员如何选择在他们的语言中实现泛型。 C# 和 Java 泛型 here 之间有一个很好的比较,如果您想了解更多信息,我强烈建议您查看。

我将对您提供的代码仅发表一条评论。您正在这一行执行未经检查的演员表:

return (T)component;

但是,由于您将 Class&lt;T&gt; 类型的对象作为参数传递,因此您可以像这样进行转换:

return tClass.cast(component);

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

【讨论】:

    【解决方案2】:

    所以我认为也许使用类型见证与捕获ClassCastException 组合使用 可能 足以做到这一点。不幸的是,即使那样,擦除也将使其成为不可能(要执行此方法没有 Class&lt;T&gt;):

    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 {}
    }
    

    【讨论】:

    • 这太复杂了。我想我就不用了
    • 这基本上只是证明(通过穷举)这是不可能的,您使用Class&lt;T&gt; 的方法是明智和正确的。
    • 哦,我看不懂,所以我认为它有效。
    【解决方案3】:

    根据 cmets 似乎认为这是不可能的,所以现在关闭了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-22
      • 2011-08-11
      • 2013-05-02
      • 1970-01-01
      • 2016-11-14
      • 1970-01-01
      • 1970-01-01
      • 2018-08-23
      相关资源
      最近更新 更多