Итак, короткий ответ: да, вы можете опускать руки. При условии, что фактический тип объекта во время выполнения является целевым типом, который вы также понижаете.
Когда ваш пример запускает return (Sub) super.f();
, он потерпит неудачу с java.lang.ClassCastException
, так как в этом случае фактический объект не является Sub
, это Super
. Вы можете увидеть это, немного изменив свой метод следующим образом:
Sub f() {
Super sup = super.f();
if(sup instanceof Sub) {
System.out.println("Instance of Sub");
} else {
System.out.println("Not an instance of Sub, it is a : " + sup.getClass());
}
return (Sub) sup;
}
Причина здесь в том, что в Super f()
вы создаете чистый объект Super
и возвращаете его, поэтому фактический тип объекта равен Super
и поскольку Super
не является Sub
, поэтому мы не можем привести его к Sub
.
Вот пример:
public class Animal {
private String type;
private int age;
public Animal(String type, int age) {
this.type = type;
this.age = age;
}
public int getAge() {
return age;
}
}
public class Cat extends Animal {
public Cat(String type, int age) {
super(type, age);
}
}
public class Dog extends Animal {
public Dog(String type, int age) {
super(type, age);
}
}
public class Vet {
public static void printHumanYears(Animal animal) {
if(animal instanceof Dog) {
Dog dog = (Dog) animal;
System.out.println("Dogs age : " + dog.getAge() * 7);
} else if(animal instanceof Cat) {
Cat cat = (Cat) animal;
System.out.println("Cat age : " + cat.getAge() * 5);
} else {
System.out.println("Not sure how to calculate age for a " + animal.getClass());
}
}
public static void main (String [] args) {
Dog dog = new Dog("Collie", 10);
Cat cat = new Cat("Tabby", 20);
Animal animal = new Animal("Animal", 20);
printHumanYears(dog);
printHumanYears(cat);
printHumanYears(animal);
}
}
Когда вызывается метод printHumanYears(Animal animal)
, ему передается объект Animal
, затем мы проверяем, к какому экземпляру относится этот объект Animal
, и затем соответствующим образом понижаем. Причина, по которой мы не получили бы ClassCastException
, заключается в том, что целевой объект (Dog
или Cat
) был создан во время выполнения. Когда мы передаем Animal
, он не может быть понижен до Dog
или Cat
, потому что это ни то, ни другое, когда он был изначально создан.
Хорошо помнить:
- Приведение не меняет фактический тип объекта.
- Приведение приводит только к изменению типа ссылки.
- Обновление всегда безопасно и никогда не приводит к ошибкам.
- Понижение не является безопасным и может вызвать
ClassCastException
, поэтому всегда хорошая идеяиспользовать instanceof
, чтобы проверить, что тип цели - это то, что вы пытаетесь разыграть.