简体   繁体   English

Java中的泛型:如何定义具有多个不同类型的函数

[英]Generic Type in java: How to define a function with multiple different type returned

@Service
public class Animal {
   public String name;
}
@Service
public class Dog extends Animal {
   public String name;
}

@Service
public class Cat extends Animal {
   public String name;
}

In spring boot project, I wanna obtain one specific bean by using ApplicationContext provided by spring framework, here is a simple example i write to illustrate: 在spring boot项目中,我想使用spring框架提供的ApplicationContext获得一个特定的bean,这是我写来说明的一个简单示例:

@Component
public class AnimalLocator implements ApplicationContextAware {
   private static ApplicationContext applicationContext;
   @Override
   public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      if (PayServiceLocator.applicationContext == null) {
         PayServiceLocator.applicationContext = applicationContext;
      }
   }

   public <T extends Animal> T getService(String name) {
      if("Cat".equals(name) {
        applicationContext.getBean(name, Cat.class);
      }
      if("Dog".equals(name) {
        applicationContext.getBean(name, Dog.class);
      }
   }
}

However, exceptions was prompted by the compiler: 但是,编译器提示了异常:

在此处输入图片说明

the mosaic part should be Dog or cat. 马赛克部分应该是狗或猫。 I thought it should work, since T has already extended the Animal class, but it doesn't ,so does anyone has any ideas about it? 我认为它应该起作用,因为T已经扩展了Animal类,但是它没有,那么有人对此有任何想法吗? Thank you! 谢谢!

Since you're using bean class to access bean instance, it's straight forward to pass class as parameter: 由于您正在使用bean类访问bean实例,因此直接将class作为参数传递是很简单的:

public <T extends Animal> T getPayService(String name, Class<T> payClass) {
   return applicationContext.getBean(name, payClass);
}

T in getPayService will extend Animal , of course. 当然, getPayService T将扩展Animal This means that code calling it with another type won't compile: 这意味着用另一种类型调用它的代码将无法编译:

Fruit fruit = animalLocator.getPayService("Banana")

To illustrate your current problem , look at this: 为了说明您当前的问题 ,请查看以下内容:

Cat cat = animalLocator.getPayService("Dog");

T is Cat in this case, but your code would be returning a Dog . 在这种情况下, TCat ,但是您的代码将返回Dog

To circumvent the compiler error, you can add a type cast: 为了避免编译器错误,可以添加类型强制转换:

return (T) applicationContext.getBean(...

But this would still not be safe because the compiler will still be unable to guarantee that the actual return type will be what T is in the context of the caller at runtime, and the caller would be having a class cast exception. 但这仍然是不安全的,因为编译器仍然无法保证实际的返回类型将是运行时调用方上下文中T值,并且调用方将具有类强制转换异常。

If we can assume that getBean is a safe call, then you should change your method to this implementation: 如果我们可以假设getBean是一个安全的调用,那么您应该将方法更改为以下实现:

public <T extends Animal> T getPayService(String name, Class<T> cls) {
   return applicationContext.getBean(name, cls);
}

This doesn't change a lot from the caller's perspective, but hinges on the fact (or assumption) that applicationContext.getBean(name, cls); 从调用者的角度来看,这并没有太大变化,而是取决于applicationContext.getBean(name, cls);的事实(或假设applicationContext.getBean(name, cls); will return an object of type T . 将返回类型T的对象。 This means your code is as type-safe as getBean is, but the compiler is happy with that. 这意味着您的代码与getBean一样具有类型安全性,但是编译器对此感到满意。

You can Autowired all your Animal instances in a Map instead of coding your if/else : 您可以将所有Animal实例自动绑定到Map中,而无需编写if / else:

@Service("Animal")
public class Animal {
    public String name;
}
@Service("Dog")
    public class Dog extends Animal {
}
@Service("Cat")
    public class Cat extends Animal {
}

And in your AnimalLocator : 在您的AnimalLocator中:

@Component
public class AnimalLocator {

   @Autowired
   private Map<String,Animal> animals;

   public <T extends Animal> T getService(String name) {
      return this.animals.get(name);
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM