【问题标题】:Paramterized class, how to reference the paramterized type of something passsed as a paramterized type参数化类,如何引用作为参数化类型传递的东西的参数化类型
【发布时间】:2015-10-21 16:28:44
【问题描述】:

对不起,如果标题很烂,不知道如何问这个问题......

假设我有一些带有参数的接口 Foo

  public interface IFoo<Bar extends IBar>{

      public Bar generateBar();
  }

我还有另一个类,它接受一个 foo 对象并将生成一个 bar 对象。我可以这样定义。

 public class FooBar<Bar extends IBar, Foo extends IFoo<Bar>>{

      private Foo foo;

      public FooBar(Foo foo){
          this.foo = foo;
      }

      public Bar getBar(){
           this.foo.generateBar();
      }

这一切都很好。但是,将 Bar 定义为 FooBar 类的参数对我来说似乎很愚蠢。 IFoo 对象将被参数化以获取 Bar 值,因此我假设我可以从 Foo 对象具有的任何参数推断 Bar 的类型;从而避免有人在每次定义 FooBar 对象时都必须提供两个参数。

有什么办法可以做到这一点吗?不是让 Bar 成为 FooBar 参数化类型的一部分,而是从 Foo 的参数中推断出来?

编辑:答案似乎是无法完成,正如已经回答的那样。但是,我将把它留到另一天,因为我希望有人可以发布一个答案,不仅可以做到,而且为什么不可能。具体来说,这仅仅是 java 开发人员从未选择支持的用例,还是有一个原因,支持其他参数化检查的相同编译时类型检查无法通过查看特定的 IFoo 类型参数来推断 Bar 类型。编译器不能确定 IFoo 参数以及任何参数化类型吗?

【问题讨论】:

  • 是的,这在使用现场很烦人。还没有看到任何好的解决方案:) 如果使用站点碰巧不需要getBar(),您可以改用FooBar&lt;?, SomeFoo&lt;SomeBar&gt;&gt; 类型。

标签: java generics


【解决方案1】:

如果您关心IFoo 的实际类型参数,那么您所拥有的就是正确的——声明类型参数Bar,这样它就可以在声明Foo 时作为IFoo 的类型参数。

但是,如果您在代码中不关心 IFoo 的类型参数是什么,那么您可以消除 Bar 类型参数并将 IFoo 的类型参数替换为通配符绑定。

class FooBar<Foo extends IFoo<? extends IBar>>{

您的getBar 方法需要返回一个IBar

public IBar getBar(){
    return this.foo.generateBar();
}

【讨论】:

  • 不错的替代方法。
  • 在很多情况下都是一个很好的解决方法(可悲的是,不是我的,我真的需要知道 Bar 的类型才能使这个方法有用),但这意味着我无法保持对 Bar 类型的了解不使用这两个参数?
  • 创建第二个类型参数Bar 是必要的,这样您就可以了解IFoo 的类型参数。
【解决方案2】:

为了有一个创建 Bar 对象的方法,您需要一个 Class&lt;Bar&gt; 类型的对象。然后你可以使用:

class FooBar ...{
    Class<Bar> barClass = ...;

    public Bar getBar(){
         return barClass.newInstance();
    }
}

获取 barClass 的方法有很多种。我不确定要推荐什么设计,因为您给了我们任意类型 Foo、Bar 等。

更通用的解决方案是:

class FooBar<T> ...{
        Class<T> someClass = ...;

        public T getInstance(){
             return someClass.newInstance();
        }
    }

您需要以某种方式将Class&lt;Bar&gt; 作为参数传递。

【讨论】:

    【解决方案3】:

    您的 getBar 方法可能会返回一个 Bar。由于类型擦除,您无法推断类型。您可以返回一个裸对象进行强制转换,但这违背了泛型的目的。

    【讨论】:

    • 但在编译时我传递了一个已经参数化的 Foo 对象。所以我已经承诺,如果我调用我的 Foo.generateBar() 它将返回一个 bar,这在编译时是已知的。因此,我们不能在编译时从 Foo 的参数化中推断 Bar 吗?
    • 我理解类型擦除,但那是在运行时。我很好奇为什么在编译时发生的参数检查不能支持这一点。请参阅我对问题的编辑。我真的很想了解编译时发生的事情可能使他们无法支持这一点。
    【解决方案4】:

    回答我自己的问题,只是提到我在特定情况下使用的方法,一种解决方法,因为我想要的东西无法完成。老实说,这很简单,所以我应该先尝试一下,但我一直想知道参数化可以做什么。

    我的 FooBar 等效项现在如下所示:

    public class FooBar<Bar extends IBar>{
    
      private IFoo<Bar> foo;
    
      public FooBar(IFoo<Bar> foo){
          this.foo = foo;
      }
    
      public Bar getBar(){
           this.foo.generateBar();
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-31
      相关资源
      最近更新 更多