【问题标题】:Java Generics Issue (w/ Spring)Java 泛型问题(带 Spring)
【发布时间】:2010-06-03 10:47:22
【问题描述】:

我想我可能是类型擦除的受害者,但我想我会先在这里与其他人核实。

我需要做这样的事情:

public interface FooFactory {
   public <T extends Bar> Foo<T> createFoo( Class<T> clazz );
}

编写这段代码是完全有效的。但是,我正在尝试使用 Spring BeanFactory 来实现此功能,但我做不到。

我想做的是这个……

public class FooFactoryImpl implements BeanFactoryAware {
   private BeanFactory beanFactory;

   public <T extends Bar> Foo<T> createFoo( Class<T> clazz ) {
      return beanFactory.getBean( ????????? );
   }

   public void setBeanFactory( BeanFactory beanFactory ) {
      this.beanFactory = beanFactory; 
   }
}

如你所见,我已经加入了?????????我想检索Foo&lt;T&gt; 类型的bean,其中T 扩展了Bar。但是,不可能派生 Foo&lt;T&gt; 类型的 Class 对象,所以我认为我想要做的事情是不可能的?

还有其他人看到解决此问题的方法或实现我正在尝试做的替代方法吗?

谢谢,

安德鲁

【问题讨论】:

  • clazz 参数是干什么用的?
  • 你为什么要尝试使用 bean factory?当然可以使用标准的 Spring 配置来实现这一点?
  • @Rob 人们有时会使用 bean 工厂来更好地控制生命周期,而不是仅仅控制惰性,或者利用原型来获取多个实例。
  • @Mar 我认为它可以提示编译器 T 是什么,因为在参数列表中没有 T 对象或 x 对象。但我很容易起雾。

标签: java generics spring


【解决方案1】:

是的,这是一种类型擦除情况。由于您无法为Foo&lt;T&gt; 获得Class,因此您必须使用Foo 并禁止显示警告。

@SuppressWarnings("unchecked")
public <T extends Bar> Foo<T> createFoo( Class<T> clazz ) {
      return (Foo<T>) beanFactory.getBean("Name of Bean", Foo.class);
}

您可能会发现this file 很有趣——它是一个实用程序类,Apache CXF 使用它来集中所有这些不幸事件。

当然,所有这些都假设您的 XML(或其他)配置将产生可用的Foo

【讨论】:

  • +1 用于在我有机会之前回答,但需要注意的是,不需要参数 clazz。
  • @你确定吗?我认为需要告诉 javac 特定调用的 T 是什么,因为参数列表中没有 T 或某物的对象。我承认我对这个话题很糊涂,如果我感到困惑,请随时编辑答案。
  • 好吧,如果您执行Foo&lt;Bar&gt; var = fooFactoryImpl.createFoo() 之类的操作,编译器会根据变量(在本例中为 Bar)推断时间。如果您想使用特定类型,您可以随时致电fooFactoryImpl.&lt;someTypeThatExtendsFoo&gt;createFoo();
  • 例如,如果您有 public &lt;T&gt; T method(Foo&lt;T&gt; foo) {//code} 并尝试像 TypeThatExtendsBar t = method(fooFactoryImpl.&lt;TypeThatExtendsBar&gt;createFoo()); 一样调用它,如果没有特定参数,它将无法工作 - 不提供参数意味着该方法返回 Bar)
  • 感谢大家的意见。肯定是一个有趣的讨论!
【解决方案2】:

由于您不能在 Spring 上下文中使用专门的 T 定义 Foo&lt;T&gt; 类型的 bean,我猜您实际上有 Foo&lt;T&gt; 的子类:

abstract public class Foo<T> { ... }

public class FooString extends Foo<String> { ... }
public class FooInteger extends Foo<String> { ... }

-

<bean id = "fooInteger" class = "FooInteger" />
<bean id = "fooString" class = "FooString" />

在这种情况下,您可以使用类型参数不会从超类定义中删除的事实:

public class FooFactory implements ApplicationContextAware {

    private Map<Class<?>, Foo<?>> beans = new HashMap<Class<?>, Foo<?>>();

    @SuppressWarnings("unchecked")
    public <T> Foo<T> createFoo(Class<T> c) {
        return (Foo<T>) beans.get(c);
    }

    @SuppressWarnings("unchecked")
    public void setApplicationContext(ApplicationContext ctx)
            throws BeansException {

        Collection<Foo> candidates = ctx.getBeansOfType(Foo.class).values();
        for (Foo candidate: candidates) {
            Type superclass = candidate.getClass().getGenericSuperclass();
            if (superclass instanceof ParameterizedType) {
                ParameterizedType t = (ParameterizedType) superclass;
                Class<?> p = (Class<?>) t.getActualTypeArguments()[0];
                beans.put(p, candidate);
            }
        }
    }
}

【讨论】:

  • 我也按照这些思路制定了一些方法。感谢您的意见。
猜你喜欢
  • 2011-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多