使用泛型时我遇到Spring问题。 以下代码描述了这个问题:
public class TestInj<S> {
S elem;
public S getElem() {
return elem;
}
public void setElem(S elem) {
this.elem = elem;
}
}
@Component
public class First extends TestInj<String> {
public First() {
setElem("abc");
}
}
@Component
public class Second extends TestInj<Integer> {
public Second() {
setElem(2);
}
}
public class BaseTest<T> {
@Autowired
protected TestInj<T> test;
}
@Named
public class Test extends BaseTest<String> {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("conf-spring.xml");
context.refresh();
Test test = (Test) context.getBean("test", Test.class);
System.out.println(test.test.getElem());
}
}
问题是,在类BaseTest中应该注入类First,因为它具有泛型类型String。但春天没有得到那个并且告诉我,有两种可能的自动装配候选者。原因是,春天忽略了泛型。是否有解决方案或解决方法?
答案 0 :(得分:7)
Spring对于泛型非常聪明,但是你的要求太高了。 Spring分析包含要注入的属性的类的泛型,即BaseTest
。但依赖项test
的类型擦除是TestInj<Object>
。只有子类Test
提供了更多通用信息,可以用于限制注入候选者。
不幸的是,它不是,Spring就是不行。在分析bean类时,Spring永远不会从它所在的层次结构中看到 down 。 (在我想在实现子类中将方法放在抽象超类和@Transactional
注释中的其他情况下,我一直反对这一点。)
因此,如果您需要该功能,则必须为Spring的核心组件之一(AutowiredAnnotationBeanPostProcessor
或其使用的辅助类之一)编写替代品。由于Spring是以模块化方式设计的,所以如果你只提供一个子类,你应该能够做到这一点而不会破坏任何东西。但是如果你不是绝对需要这个功能,那么简单的答案就是:“它不能那样工作”: - )
答案 1 :(得分:-1)
这是由于类型擦除。参见:
http://download.oracle.com/javase/tutorial/java/generics/erasure.html
When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a process where the compiler removes all information related to type parameters and type arguments within a class or method. Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics.
由于Spring DI容器在运行时工作,因此无法区分这些类型。