JAVA-объект приведения к классу, заданный именем определенного супертипа - PullRequest
0 голосов
/ 24 января 2019

Например, у меня есть суперкласс Animal в мастер-пакете и подклассы Dog и Cat в определенных банках.Все классы являются сущностями JPA.

public class Animal {
}

public class Dog extends Animal{
}

public class Cat extends Animal{
}

У меня есть метод, который получает Animal в качестве параметра.

public createAnimal(Animal a){
   this.em.persist(a);
}

Теперь я хочу передать объект типа Dog или Cat этому методу

Animal a = ... //read from somewhere...
String myClass = "my.package.Dog";// at runtime
Class specific = Class.forName(myClass);
createAnimal(specific.cast(a));

Я не могу импортировать Dog и Cat в свой мастер-пакет, потому что он должен быть универсальным (я использую его в других EAR).

Итак, как я могу привести к определенным классам, определенным по имени, и дать системе знать, что это подтип Animal?

Мне нужно что-то вроде этого:

Class<Animal> specific = Class.forName(myClass);

но я что-то упускаю.

1 Ответ

0 голосов
/ 24 января 2019

Вы, похоже, не понимаете, что делает кастинг. Синтаксис приведения, который выглядит следующим образом: (Dog) someAnimal; делает 3 совершенно не связанные вещи.

1) Первое, что он делает, это приведение типов, которое фактически преобразует значение из одного вида в другой. Вы получаете это ТОЛЬКО ЕСЛИ вещь в паренсе примитивна. Пример: int x = (int) 5.5; «принудит» 5,5 (что является двойным) для преобразования в 5 (целое число).

2) Второе, что он делает, это проверка типа. Это то, что происходит, когда вещь в скобках является не примитивным типом, а не типом, который менее специфичен, чем выражение. Так, например: Animal a = someAnimal(); Dog d = (Dog) a;. Вы, кажется, думаете, что эта операция превращает животное в собаку. Это не. Все это делает проверку типов: a является переменной типа Animal, и все это означает, что она либо указывает на ноль, либо указывает на какой-либо объект, который является экземпляром Animal (класса) самого или любой его подтип . Для 'a' совершенно нормально иметь тип Animal и указывать на объект типа Cat (который является подтипом Animal). Запись (Dog) a будет проверять тип: если a в данный момент указывает на какой-либо экземпляр класса Dog или null, эта операция вообще ничего не делает. Если он НЕ указывает на собаку (скажем, он указывает на кошку), это выражение вызовет выброс ClassCastException. Ни в коем случае эта операция никогда не преобразует ничего .

  1. Последнее, наиболее эзотерическое использование - это когда вы делаете что-то вроде: Dog d = someDog(); Animal a = (Animal) d;. В большинстве случаев это полный запрет, и ваша IDE предупредит вас, что делать это совершенно бессмысленно; просто Animal a = d; так же законно. Тем не менее, тип все еще меняется, что может повлиять на то, какой метод вы вызываете и на какие лямбды будут набираться. Если это для вас пустяк, не беспокойтесь об этом; это происходит в принципе никогда.

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

Единственное допустимое присвоение переменной Class<Animal>, это Animal.class (и ноль). Dog.class там не пускают. Если это было ваше намерение, правильный тип - Class<? extends Animal>.

Вы можете разыграть INSTANCES с помощью метода cast любого класса. Например:

Dog dog = Dog.class.cast(someAnimal());
Dog dog = (Dog) someAnimal();

полностью эквивалентны: это ничего не делает, если только someAnimal () не возвращает не собаку, и в этом случае это вызовет исключение ClassCastException.

Если вы хотите проверить, совместим ли какой-либо экземпляр класса с animal, вы можете сделать это:

Class<?> dogClass = Dog.class;
if (!Animal.class.isAssignableFrom(dogClass)) { /* error here */ }

В качестве альтернативы есть asSubclass:

Class<? extends Animal> animalClass = Dog.class;
Class<? extends Dog> dogClass = animalClass.asSubclass(Dog.class);
assert dogClass == animalClass;

Обратите внимание, что метод asSubclass снова ничего не делает, он просто заставляет javac перестать жаловаться. Во время выполнения дженерики исключаются; это всего лишь Class, бит в <> исчез. Следовательно, dogClass и animalClass - это две переменные, которые указывают на один и тот же объект (а именно, экземпляр j.l.Class, представляющий ваш класс Dog).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...