Общий тип в Java: как определить функцию с несколькими различными типами возвращаемых - PullRequest
0 голосов
/ 22 февраля 2019
@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;
}

В весеннем загрузочном проекте я хочу получить один конкретный bean-компонент с помощью ApplicationContext, предоставленного Spring Framework, вот простой пример, который я пишу для иллюстрации:

@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);
      }
   }
}

Однако исключения были вызваныкомпилятор:

enter image description here

часть мозаики должна быть Dog или Cat.Я думал, что это должно работать, так как T уже расширил класс Animal, но это не так, у кого-нибудь есть какие-либо идеи по этому поводу?Спасибо!

Ответы [ 3 ]

0 голосов
/ 22 февраля 2019

T в getPayService будет расширяться Animal, конечно.Это означает, что код, вызывающий его с другим типом, не будет компилироваться:

Fruit fruit = animalLocator.getPayService("Banana")

Чтобы проиллюстрировать вашу текущую проблему , посмотрите на это:

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

T в данном случае Cat, но ваш код будет возвращать Dog.

Чтобы обойти ошибку компилятора, вы можете добавить приведение типа:

return (T) applicationContext.getBean(...

Но этовсе равно не будет безопасным, потому что компилятор по-прежнему не сможет гарантировать, что фактический тип возвращаемого значения будет таким, как T в контексте вызывающего во время выполнения, и у вызывающего будет исключение приведения класса.

Если мы можем предположить, что getBean является безопасным вызовом, то вы должны изменить свой метод на эту реализацию:

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

Это не сильно изменится с точки зрения вызывающего, но зависит отфакт (или предположение), что applicationContext.getBean(name, cls); вернет объект типа T.Это означает, что ваш код безопасен по типу, как getBean, но компилятор этим доволен.

0 голосов
/ 22 февраля 2019

Вы можете автоматически связать все свои экземпляры животных на карте вместо того, чтобы кодировать свой if / else:

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

А в вашем AnimalLocator:

@Component
public class AnimalLocator {

   @Autowired
   private Map<String,Animal> animals;

   public <T extends Animal> T getService(String name) {
      return this.animals.get(name);
   }
}
0 голосов
/ 22 февраля 2019

Поскольку вы используете класс бина для доступа к экземпляру бина, просто передать класс в качестве параметра:

public <T extends Animal> T getPayService(String name, Class<T> payClass) {
   return applicationContext.getBean(name, payClass);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...