Вы, похоже, не понимаете, что делает кастинг. Синтаксис приведения, который выглядит следующим образом: (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
. Ни в коем случае эта операция никогда не преобразует ничего .
- Последнее, наиболее эзотерическое использование - это когда вы делаете что-то вроде:
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).