То, что сказал Умберто Коззи, правильно, это связано с тем, что вы ссылаетесь на открытое значение в конструкторе. Если вы пройдете по коду, вы увидите, что последовательность событий:
- Вы вызываете конструктор
Student
, передавая значение для age
.
- Первое, что делает конструктор ( до создания объекта
Student
), - это вызов конструктора суперкласса.
- Во время создания суперкласса (
Person
) вы попали в эту строку кода: val dob = thisyear - age
. age
- это открытый член (то есть переопределенный в подклассе, Student
). Таким образом, значение должно быть получено из Student
. Проблема в том, что на данный момент Student
еще не полностью сконструирован (вспомните первое, что сделал его конструктор - это вызов конструктора суперкласса). Поэтому Person
не может спросить Student
, какое значение age
должно быть, так как это значение еще не установлено. Если вы шагаете по коду и проверяете значение age
в этой строке кода, оно равно нулю (значение по умолчанию для Int
).
Итак, вопрос в том, что делать? И я думаю, что вы должны спросить: почему Student
переопределяет age
(и действительно firstname
и surname
). Есть ли различия в поведении age
, firstname
и surname
между Person
и Student
? Ответ, вероятно, нет. Поэтому Student
не должен переопределять эти свойства: вместо этого он должен объявлять их просто как параметры конструктора (без val
или var
) и передавать эти значения в базовый класс. Другими словами, Student
должно выглядеть следующим образом:
class Student(firstname: String, surname: String, age: Int, val studentID: Int) :
Person(firstname, surname, age) {
...
Вы также можете знать, что ваша строка кода, которая объявляет thisyear
, на самом деле создает свойство Person
, которое называется thisyear
, что, я полагаю, вам не нужно. Любые val
или var
члены, которые объявлены непосредственно в классе (а не в функции), являются объявлением свойства (и именно поэтому все это вычисляется непосредственно во время создания объекта Person
) , Так что, возможно, вы захотите добавить это как:
val dob = Calendar.getInstance().get(Calendar.YEAR) - age
Если вычисление является более сложным и требует больше строк кода, просто создайте закрытый метод (например, calculateDob
) и вызовите его, например, val dob = calculateDob(age)
Есть также небольшая аномалия, что age
- это var
(то есть может измениться), тогда как dob
- это val
(то есть не может измениться). Таким образом, пользователь может изменить значение age
, но dob
не будет обновлено. Один из возможных способов решить эту проблему - изменить dob
, чтобы вместо свойства, которому в процессе конструирования было присвоено значение (только для чтения), сделать его свойством с помощью метода получения, который будет вычислять значение при каждом вызове, например,
val dob
get() = Calendar.getInstance().get(Calendar.YEAR) - age
Другой вариант - добавить вспомогательное поле и метод получения / установки для age
и обновлять dob
всякий раз, когда age
обновляется.