JavaRush /Java блог /Random UA /Перетворення типів посилань на Java
Sant9Iga
41 рівень

Перетворення типів посилань на Java

Стаття з групи Random UA
Доброго часу, джаварашовець. Почали мені надходити питання про приведення типів посилань в Java. Що б щоразу не переказувати те саме, вирішив написати маленьку статтю.

Спочатку розберемо, що таке приведення типів

Приведення типів (перетворення типів) — перетворення значення змінної одного типу на значення іншого типу. Погляньмо на прикладі, що це таке і з чим його їдять. У нас є деяка ієрархія класів ( див. рисунок 1 ). Тут видно всі класи ієрархії, хто успадковує і методи кожного класу. Малюнок 1Є розширювальне та звужувальне приведення. Ми бачимо, що клас Catє спадкоємцем класу Pet. Pet, своєю чергою, спадкоємець класу Animal. Коли ми напишемо:
Animal animalCat = new Cat();
Animal animalDog = new YorkshireTerrier();
Це розширююче приведення (чи неявне). Ми розширабо посилання animalCatта animalDog. Вони посилаються на об'єкти Catта Dog. При такому наведенні ми не можемо через посилання animalCat/animalDogвикликати методи, які є в Cat/Dog, але яких немає в Animal. Звуження приведення (або явне) відбувається у зворотний бік:
Animal animalCat = new Cat();
Animal animalDog = new YorkshireTerrier();
Cat cat =(Cat)animalCat;
YorkshireTerrier dog = (YorkshireTerrier) animalDog;
Ми явно вказали до якого типу хочемо навести цей об'єкт. BUT, BE CAREFUL! Якщо Ви зробите так:
Animal animalCat = new Cat();
YorkshireTerrier dog = (YorkshireTerrier) animalCat;
компілятор пропустить цей код. А ось RunTimeвикине вам:
Exception in thread "main" java.lang.ClassCastException: Animals.Cat cannot be cast to Animals.YorkshireTerrier
RunTimeбачить, що Catй YorkshireTerrierдва різні класи. Щоб уникнути ClassCastException при звужуванні, використовуйте instanceof.
Animal animalCat = new Cat();
if (animalCat instanceof YorkshireTerrier)
{
    YorkshireTerrier dog = (YorkshireTerrier) animalCat;
}
Якщо animalCatє YorkshireTerrier, тоді відбудеться присвоєння, якщо ні – нічого не станеться.

А тепер навіщо це потрібно, якщо ми втрачаємо методи і можемо отримати такі помилки

Розглянемо код, який я зробив за діаграмою з Мал. 1 . КласAnimal
public abstract class Animal
{
    String name;
    int age;
    String nameOfClass = getClass().getSimpleName();
    public void eat(){
        System.out.println(nameOfClass + ": Omnomnom");
    }
    public void sleep(){
        System.out.println(nameOfClass + ": Z-z-z-z");
    }
}
Клас WildAnimalякий успадковується відAnimal
public abstract class WildAnimal extends Animal
{
    public void steelChicken()
    {
        System.out.println(nameOfClass+": Muhaha,I stole a chicken!");
    }
}
Клас Petякий успадковується відAnimal
public abstract class Pet extends Animal
{
    public void peeInTray(){
        System.out.println(nameOfClass + ": Master, I peed");
    }
}
Клас Foxякий успадковується відWildAnimal
public class Fox extends WildAnimal
{
    public void eatColobok(){
        System.out.println(nameOfClass + ": I will eat you, Colobok");
    }
}
Клас Wolfякий успадковується відWildAnimal
public class Wolf extends WildAnimal
{
    public void hawlAtTheMoon(){
        System.out.println(nameOfClass + ": Ouuuuu!!!Ouuuu!!!");
    }
}
Клас Catякий успадковується відPet
public class Cat extends Pet
{
    public void sleepOnKeyboard(){
        System.out.println(nameOfClass + ": Master, stop working!!I wanna sleep on your keyboard");
    }
}
Клас YorkshireTerrierякий успадковується відPet
public class YorkshireTerrier extends Pet
{
    public void bark(){
        System.out.println(nameOfClass + ": Meow!!! Meow!!!");
    }
}
Уявіть собі ситуацію. Нам потрібно зібрати всіх тварин в один список, нагодувати їх і потім укласти спати. Це легко зробити, якщо ми створимо ArrayListтварин ( Animal). І потім у кожної тварини викличемо відповідні методи:
public class ZOO
{
    public static void main(String[] args)
    {
        List<Animal> allAnimals = new ArrayList<>();
        allAnimals.add(new Cat());
        allAnimals.add(new Wolf());
        allAnimals.add(new Fox());
        allAnimals.add(new YorkshireTerrier());
        for (Animal animal : allAnimals)
        {
            animal.eat();
            animal.sleep();
        }
    }
}
Я не можу animalвикликати метод bark()або sleepOnKeyboard(). Тому що в листі allAnimalsзберігаються кіт, вовк, йорік та лисиця, але вони приведені до Animal. І вони мають лише ті методи, які є в Animal. Це дуже добре, тому що, якби ми могли викликати всі методи, то навіщо нам потрібен вовк, який спить на клавіатурі, чи йорік, який краде курок? Дякую за увагу. Сподіваюся, ця стаття для Вас буде корисною. Критика та коментарі вітаються)
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ