iterator получает значение родительского класса

Рейтинг: -1Ответов: 2Опубликовано: 22.03.2023

Main: при прохождении iteratorом по petListIter для pets.kind == получаю значение null. По дебагеру вижу, что значение kind берется из родительского класса Pet, которое в поле String kind не обозначено, т.е. действительно == null. С чем это cвязано, где прочитать? Kак исправить код чтобы значение kind бралось из дочернего класса т.е. Cat || Dog || Parrot ?

public class Main {
    public static void main(String[] args) {
        List<Pet> petList = new ArrayList<>();
        Pet cat1 = new Cat( 2, "bl", "cat#1");
        petList.add(cat1);
        Pet cat2 = new Cat( 1, "red", "cat#2");
        petList.add(cat2);
        Pet cat3 = new Cat( 3, "wh", "cat#3");
        petList.add(cat3);
        Pet cat4 = new Cat( 0, "rand", "cat#4");
        petList.add(cat4);
        Pet dog1 = new Dog("dog", 2, "br", "dog#1");
        petList.add(dog1);
        Pet dog2 = new Dog("dog", 5, "bl", "dog#2");
        petList.add(dog2);
        Pet dog3 = new Dog("dog", 4, "bl", "dog#3");
        petList.add(dog3);
        Pet dog4 = new Dog("dog", 10, "wh", "dog#4");
        petList.add(dog4);
        Pet parrot1 = new Parrot("parrot", 1, "gr", "parrot#1");
        petList.add(parrot1);
        Pet parrot2 = new Parrot("parrot", 1, "ye", "parrot#2");
        petList.add(parrot2);

        List<Pet> catList = new ArrayList<>();
        List<Pet> dogList = new ArrayList<>();

        Iterator<Pet> petListIter = petList.iterator();
        while (petListIter.hasNext()) {
            Pet pets = petListIter.next();
            System.out.println(pets.kind);
            if (pets.kind == "cat") catList.add(pets);
            else if (pets.kind == "dog") dogList.add(pets);
            else if (pets.kind == "parrot") petList.remove(pets);
            }
    }
}
    public class Pet {
    protected String kind;
    protected int age;
    protected String color;
    protected String name;

}
public class Cat extends Pet {
    protected String kind = "cat";
    protected int age;
    protected String color;
    protected String name;

    public Cat(int age, String color, String name) {
        this.age = age;
        this.color = color;
        this.name = name;
    }
}
public class Dog extends Pet {
    protected String kind = "dog";
    protected int age;
    protected String color;
    protected String name;

    public Dog(String kind, int age, String color, String name) {
        this.kind = kind;
        this.age = age;
        this.color = color;
        this.name = name;
    }
}
public class Parrot extends Pet {
    protected String kind = "parrot";
    protected int age;
    protected String color;
    protected String name;

    public Parrot(String kind, int age, String color, String name) {
        this.age = age;
        this.color = color;
        this.name = name;
    }
}

Ответы

▲ 0Принят
  1. У вас в иерархии классов все поля (а не только kind) перекрываются по нескольку раз в классах-потомках, вместо того, чтобы определить поле один раз.
  2. Поле kind не несёт особого смысла, по сути дублируя название класса.
  3. Сравнение строк вида pets.kind == "cat" может не отработать, для строк следует использовать equals, а в целом практичнее использовать отдельный enum, для упрощения сравнения.
enum PetKind {PET, DOG, CAT, PARROT;}

public class Pet {
    protected PetKind kind;
    protected int age;
    protected String color;
    protected String name;

    public Pet(PetKind kind, int age, String color, String name) {
        this.kind = kind;
        this.age = age;
        this.color = color;
        this.name = name;
    }

    public Pet(int age, String color, String name) {
        this(PetKind.PET, age, color, name);
    }
}

Тогда код классов потомков значительно упрощается, главное вызвать нужный конструктор:

public class Cat extends Pet {
    public Cat(int age, String color, String name) {
        super(PetKind.CAT, age, color, name);
    }
}

public class Dog extends Pet {
    public Dog(int age, String color, String name) {
        super(PetKind.DOG, age, color, name);
    }
}

public class Parrot extends Pet {
    private int wingSize;  // размах крыла - доп. поле
    public Parrot(int age, String color, String name, int wingSize) {
        super(PetKind.PARROT, age, color, name);
        this.wingSize = wingSize;
    }
}

Соответственно, никаких проблем с итератором не возникнет. Следует также заметить, что следует удалять элементы при помощи Iterator::remove, а не List::remove

Iterator<Pet> petListIter = petList.iterator();
while (petListIter.hasNext()) {
    Pet pet = petListIter.next();
    System.out.println(pets.kind);

    switch (pets.kind) {
        case CAT: catList.add(pet); break;
        case DOG: dogList.add(pet); break;
        case PARROT: petListIter.remove(); break;
    }
}
▲ 0

У Вас объявлено поле kind в родительском и дочернем классах, поэтому при обращении к объекту как к Pet, вы получаете значение из объекта класса Pet и оно равно null т.к. Вы его не задаете в коде.
На самом деле, Вам необходимо определить поле kind только у класса Pet и задавать его в конструкторах дочерних классов.
Вообще, лучше избегать перекрывания (shadowing) полей и переменных, т.к. это может приводить к различным не очень очевидным ошибкам.

Вот тут, как-раз описан Ваш случай на конкретном примере: https://javahungry.blogspot.com/2020/02/variable-shadowing-and-variable-hiding.html