iterator получает значение родительского класса
Main: при прохождении iterator`ом по petListIter для pets.kind == получаю значение null. По дебагеру вижу, что значение kind берется из родительского класса Pet, которое в поле String kind не обозначено, т.е. действительно == null. С чем это cвязано, где прочитать? и как исправить код чтобы значение бралось из дочернего класса?
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;
}
}
Ответы (2 шт):
У Вас объявлено поле kind в родительском и дочернем классах, поэтому при обращении к объекту как к Pet, вы получаете значение из объекта класса Pet и оно равно null т.к. Вы его не задаете в коде.
На самом деле, Вам необходимо определить поле kind только у класса Pet и задавать его в конструкторах дочерних классов.
Вообще, лучше избегать перекрывания (shadowing) полей и переменных, т.к. это может приводить к различным не очень очевидным ошибкам.
Вот тут, как-раз описан Ваш случай на конкретном примере: https://javahungry.blogspot.com/2020/02/variable-shadowing-and-variable-hiding.html
- У вас в иерархии классов все поля (а не только
kind) перекрываются по нескольку раз в классах-потомках, вместо того, чтобы определить поле один раз. - Поле
kindне несёт особого смысла, по сути дублируя название класса. - Сравнение строк вида
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;
}
}