Фактический конструктор для DiscountProduct
, если рассматривать его как код Java, будет выглядеть примерно так:
public DiscountProduct(@NotNull Discount discount, @NotNull String productName_param, double price_param) {
Intrinsics.checkParameterIsNotNull(discount, "discount");
Intrinsics.checkParameterIsNotNull(productName_param, "productName_param");
super(productName_param, price_param);
this.discount = discount;
}
Таким образом, конструктор super
(т.е. конструктор Product
) сначала вызывается, а затем инициализируется discount
член. Конструктор
Product
выглядит примерно так:
public Product(@NotNull String productName, double price) {
Intrinsics.checkParameterIsNotNull(productName, "productName");
super();
this.productName = productName;
this.price = price;
this.profit = this.getPrice();
}
Когда вы получаете this.profit = this.getPrice();
(что соответствует kotlin line val profit = price
) вы вызываете метод DiscountProduct
getPrice
, который пытается использовать элемент discount
, который еще не был инициализирован. И именно поэтому вы получаете NullPointerException
.
Вероятно, есть несколько различных способов, которыми вы могли бы это исправить. Одним из возможных решений было бы сделать profit
ленивым свойством, чтобы оно не инициализировалось до тех пор, пока вы в первый раз не попытаетесь его использовать:
val profit: Double by lazy { price }
Другое возможное решение будет:
val profit: Double get() = price
Разница между этим и ленивым свойством заключается в том, что здесь цена рассчитывается каждый раз, когда вы используете profit
, а не только в первый раз.