Абстрактный val с аннотацией в kotlin android

Могу я написать:

@IdRes
abstract fun getHeaderId(): Int

С val вместо fun в котлине? Он жалуется, что мне нужно поле поддержки или делегат, когда я пишу:

@IdRes <-- errors
abstract val headerId: Int

Что в данном случае наиболее идиоматично? Однострочный с fun или возиться с резервным полем (я не привык к резервным полям, возможно, это устойчивость к изменениям, я никогда не использовал их, поэтому я думаю, что они неприятны)

18
0
3 314
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Поскольку абстрактный val или var - это просто функция без поля поддержки, она не может быть аннотирована аннотацией IdRes, но есть обходной путь. Вы можете использовать это так:

@get:IdRes
abstract val headerId: Int

Обновлено:

Почему это работает? Нам нужно внимательнее изучить аннотацию IdRes и ее исходный код:

@Documented
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE})
public @interface IdRes {
}

Как мы видим, эту аннотацию можно использовать для методов, параметров, полей и локальных переменных. Когда мы используем abstract val, он не является ни тем, ни другим, поскольку он абстрактный, и у нас не может быть абстрактных полей в Java. Обычно эквивалент abstract val something: Int в Java:

private int something

public int getSomething() {
    return something;
}

Из примера легко увидеть, что частное поле - это то, что называется резервным полем свойства, и вы не можете иметь их как абстрактные, поэтому в этом и заключалась проблема.

Но в этом случае кто-то, использующий абстрактный класс, может обойти аннотацию, просто написав override val headerId: Int = 5 в своей реализации абстрактного класса.

Atul Gupta 09.06.2019 09:35

Я только что наткнулся на этот пост с той же проблемой (за исключением того, что мой val находится в интерфейсе) и пришел к тому же решению, но на самом деле оно не работает. в классах, которые реализуют мой интерфейс и переопределяют этот val, аннотация не принимается во внимание, и я могу передать любой int

or_dvir 25.05.2020 11:01

Как упоминалось в комментарии @AtulGupta, ответ @theKarlo не заставляет подкласс передать IdRes.

Следовательно, альтернатива

@IdRes
abstract fun getHeaderId(): Int

и

@get:IdRes
abstract val headerId: Int

Это передать значение в конструктор самого класса, чтобы можно было избежать проблемы с полем поддержки и чтобы подкласс был вынужден передать IdRes.

Например:

abstract class SomeClass(@IdRes val idRes: Int)

Другие вопросы по теме