Установка расширения котлина

Я не уверен, возможно ли установить расширение kotlin как объект Java.

В моей программе у меня есть класс java с именем Submission, и я хотел создать расширение kotlin для него с именем categories — ArrayList — поэтому я сделал это так.

var Submission.categories: ArrayList<String>
    get() {
        return this.categories
    }
    set(categories){
        this.categories = categories
    }

Однако всякий раз, когда я пытаюсь установить категорию, программа просто вылетает с ошибкой stackOverflowError следующим образом:

ERR: stack=java.lang.StackOverflowError: stack size 8MB
             at com.....setCategories(Extensions.kt:0)
             at com.....setCategories(Extensions.kt:19)
             at com.....setCategories(Extensions.kt:19)
             at com.....setCategories(Extensions.kt:19)
             at com.....setCategories(Extensions.kt:19)
             at com.....setCategories(Extensions.kt:19)

Похоже, это правильный синтаксис для объявления расширений kotlin. Поэтому я действительно не уверен, в каком направлении мне следует идти, чтобы исправить это. Возможно, мне действительно следует просто использовать простое старое наследование?

Спасибо.


person nmu    schedule 19.12.2016    source источник
comment
Вы не определяете какую-либо пользовательскую логику в геттерах в сеттерах, так зачем они вам нужны? Проблема вызвана неправильным объявлением установщика, this.categories = categories вызовет метод set(), что приведет к бесконечному циклу.   -  person Egor    schedule 19.12.2016
comment
@ Егор А, это имеет смысл. Причина, по которой я определил методы get и set, заключается в том, что он отказывается компилироваться без метода get и оператора return. Я предположил, что это было то же самое для набора, а также и сделал это тоже. Я собираюсь попробовать удалить установленную логику и посмотреть, что произойдет.   -  person nmu    schedule 19.12.2016


Ответы (1)


Ваш код выдает StackOverflowError, потому что он рекурсивно вызывает сам себя. this.categories просто вызывает геттер, в котором он уже находится, а this.categories = categories вызывает сеттер, в котором он уже находится.

Свойства расширения — это всего лишь синтаксический сахар для пары (расширений) геттеров и сеттеров. Внутри средств доступа к свойствам (т.е. геттер и сеттер) вы можете получить доступ только к тому, что уже publicдоступно из класса получателя. Если у него есть общедоступные поля, вы можете получить к ним доступ, однако вы не можете определить новые поля. Если вы хотите сохранить дополнительное состояние, но у класса нет API для этого, вам не повезло.

Что обычно делает изменяемое свойство расширения, так это перенаправление на существующие изменяемые функции. Вот пример.

//java
class Foo {
    private List<String> items;

    public String myItems() {
        return items;
    }
}


//kotlin
var Foo.firstItem: String
    get() = myItems()[0]
    set(value) {
        myItems()[0] = value
    }
person Kirill Rakhman    schedule 19.12.2016
comment
Даже после изменения моих геттеров и сеттеров, чтобы избежать рекурсивного вызова, как вы указали. StackOverflowError просто переходит к функции get(). Однако, если я правильно понимаю ваш пост, это все равно не должно работать, потому что categories не является общедоступным полем в этой программе, я пытался определить новое поле. Так что я думаю, что это корень проблемы. - person nmu; 19.12.2016
comment
Я полностью согласен с этим ответом, но, возможно, стоит упомянуть, что, хотя расширения не могут изменять класс для добавления резервных полей, дополнительное состояние все же может храниться где-то вне класса, и здесь могут помочь делегаты. Дополнительные сведения об этом временном решении см. на странице stackoverflow.com/a/36511438/2196460. - person hotkey; 19.12.2016
comment
@hotkey спасибо за ссылку. Чтобы быть уверенным, будет ли это работать и с классами Java - person nmu; 19.12.2016
comment
@nmu, да, будет, вы также можете определить расширения Kotlin для классов Java. Если вам нужно использовать эти расширения в Java, они видны как статические функции. Например, расширение tag, определенное для MyClass в KotlinFile.kt, будет отображаться как KotlinFileKt.getTag(MyClass $receiver) и аналогичный установщик. - person hotkey; 19.12.2016
comment
@hotkey Ах, отлично. Собираюсь попробовать это сейчас. Благодарим за помощь - person nmu; 19.12.2016
comment
Фрагмент кода в моем ответе на самом деле содержит класс Java. - person Kirill Rakhman; 19.12.2016