Как переопределить поле унаследованного класса другого типа

Как переопределить поле унаследованного класса Second другого типа

public class First{
  private int id; 
 
 
  public int getId() {
    return id;
  }
 
 
  public void setId(int id) {
    this.id= id;
  }
}
public class Second extend First{
  private String id;
 
  @Override
  public String getId() {
    return id;
  }
 
 
  public void setId(String id) {
    this.id= id;
  }
}

Ответы (1 шт):

Автор решения: Nowhere Man

Переопределить метод в дочернем классе, отличающийся только типом возвращаемого значения, можно если типы результатов в методах First::getId Second::getId являются совместимыми. Общим для типов String и int является Object, так что, расширив тип до Objectв родительском классе можно заставить код скомпилироваться:

class First{
  private int id; 
 
  public Object getId() {
    return id;
  }
 
  public void setId(int id) {
    this.id= id;
  }
}

class Second extends First{
  private String id;
 
  @Override
  public String getId() {
    return id;
  }
 
 
  public void setId(String id) {
    this.id= id;
  }
}

Однако в такой реализации может быть побочный эффект, так как в дочернем классе возникает перегрузка сеттеров: два метода setId, но только 1 геттер.

First f = new First();
f.setId(1);
System.out.println(f.getId()); // -> 1

First f2 = new Second();
f2.setId(12);    // вызывается доступный "родительский" сеттер
//f2.setId("b"); // такой метод не определён в классе First!
System.out.println(f2.getId()); // -> null

Во втором случае дочерний геттер будет возвращать null, так как у переменной с типом родителя нельзя вызвать напрямую сеттер со строковым аргументом.

((Second) f2).setId("b"); // явное приведение к дочернему типу для вызова сеттера
System.out.println(f2.getId()); // -> b

"Потерянное" значение в дочернем классе:

Second s = new Second();
s.setId(2);   // неизвлекаемое значение
s.setId("x");
System.out.println("child: " + s.getId());            // -> child: x
System.out.println("parent: " + ((First) s).getId()); // -> parent: x

Поэтому для доступа к целочисленному значению в родительском классе всё равно может потребоваться отдельный геттер:

class FIrst {
// ...
    public final int getIntId() { return this.id; }
}
→ Ссылка