Геттеры и сеттеры в Котлине


86

В Java, например, я могу писать геттеры самостоятельно (сгенерированные IDE) или использовать аннотации, такие как @Getter в ломбоке, что было довольно просто.

Однако в Kotlin по умолчанию есть геттеры и сеттеры . Но я не понимаю, как их использовать.

Я хочу сделать это, скажем так - аналогично Java:

private val isEmpty: String
        get() = this.toString() //making this thing public rises an error: Getter visibility must be the same as property visibility.

Итак, как работают геттеры?

Ответы:


142

Геттеры и сеттеры автоматически генерируются в Котлине. Если вы напишете:

val isEmpty: Boolean

Он равен следующему коду Java:

private final Boolean isEmpty;

public Boolean isEmpty() {
    return isEmpty;
}

В вашем случае модификатор частного доступа является избыточным - isEmpty по умолчанию является закрытым и доступен только для геттера. Когда вы пытаетесь получить свойство isEmpty вашего объекта, вы действительно вызываете метод get. Для лучшего понимания геттеров / сеттеров в Kotlin: два примера кода ниже равны:

var someProperty: String = "defaultValue"

а также

var someProperty: String = "defaultValue"
    get() = field
    set(value) { field = value }

Также хочу отметить, что thisв геттере не ваша собственность - это экземпляр класса. Если вы хотите получить доступ к значению поля в геттере или сеттере, вы можете использовать fieldдля него зарезервированное слово :

val isEmpty: Boolean
  get() = field

Если вы хотите, чтобы в открытом доступе был только метод get - вы можете написать этот код:

var isEmpty: Boolean
    private set 

из-за модификатора private рядом с набором доступа вы можете установить это значение только в методах внутри вашего объекта.


16
In your case the private access modifier is redundantКак? В документе Kotlin говорится, что модификатор по умолчанию является общедоступным. kotlinlang.org/docs/reference/visibility-modifiers.html

@ Ничего, да, похоже, это публичное поле, но под капотом вы вызываете метод получения
Cortwave

Не val isEmpty: Booleanбудет компилироваться, поскольку isEmpty еще не инициализирован, верно? Только начинаю изучать Котлин. Кроме того, что происходит с get() = field?
Шубхам А.

1
У @Chiara valнет сеттера
chroder

@chroder да, вы правы, наверное, я неправильно прочитал ... комментарий удален. Спасибо, что указали на это
Кьяра

30

Правила относительно модификаторов видимости средств доступа к свойствам следующие:

  • Видимость получателя varи valсвойство должны быть точно такими же, как видимость свойства, поэтому вы можете только явно дублировать модификатор свойства, но он является избыточным:

    protected val x: Int
        protected get() = 0 // No need in `protected` here.
    
  • Видимость varсвойства Setter должна быть такой же или менее разрешительной, чем видимость свойства:

    protected var x: Int
        get() = 0
        private set(x: Int) { } // Only `private` and `protected` are allowed.
    

В Kotlin доступ к свойствам всегда осуществляется через геттер и сеттер, поэтому нет необходимости создавать свойство privateс помощью publicаксессоров, как в Java - его вспомогательное поле (если оно есть) уже является закрытым. Таким образом, модификаторы видимости в средствах доступа к свойствам используются только для того, чтобы сделать видимость установщика менее разрешающей:

  • Для свойства с резервным полем и средствами доступа по умолчанию:

    var x = 0 // `public` by default
        private set
    
  • Для собственности без резервного поля:

    var x: Int // `public` by default
        get() = 0
        protected set(value: Int) { }
    

Можно ли установить и получить разные типы? Устанавливать x равным некоторому "Some String"и возвращать, скажем, длину 11строки?
Carel

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

Черт, Kotlin настолько близок к Python, что вы думаете, что он просто сработает, когда вам напомнят, что он напечатан ... и перережете себе глотку.
Carel

Спасибо за модификаторы доступа. Я удалил privateпеременную, и она стала доступна из другого класса с помощью геттера.
CoolMind

Я получаю сообщение «Частные сеттеры не разрешены для открытых свойств» при использовании комбинации «var x // private set». Решено объявлением "final var x"
Tom

14

1) Пример по умолчанию setterи getterдля собственности firstName в Котлине

class Person {
    var firstName: String = ""
            get() = field       // field here ~ `this.firstName` in Java or normally `_firstName` is C#
            set(value) {
                field = value
            }

}

С помощью

val p = Person()
p.firstName = "A"  // access setter
println(p.firstName) // access getter (output:A)

Если ваш setterили getterэто точно так же выше, вы можете удалить его , потому что это ненужное

2) Пример настраиваемого сеттера и получателя.

const val PREFIX = "[ABC]"

class Person {

    // set: if value set to first name have length < 1 => throw error else add prefix "ABC" to the name
    // get: if name is not empty -> trim for remove whitespace and add '.' else return default name
    var lastName: String = ""
        get() {
            if (!field.isEmpty()) {
                return field.trim() + "."
            }
            return field
        }
        set(value) {
            if (value.length > 1) {
                field = PREFIX + value
            } else {
                throw IllegalArgumentException("Last name too short")
            }
        }
}

С помощью

val p = Person()
p.lastName = "DE         " // input with many white space
println(p.lastName)  // output:[ABC]DE.
p.lastName = "D" // IllegalArgumentException since name length < 1

Подробнее
Я начинаю изучать Kotlin с Java, поэтому я не понимаю, fieldи propertyпотому что в Java нет property.
После некоторого поиска я вижу fieldи propertyв Kotlin выглядит как C # (в чем разница между полем и свойством? )

Вот некоторые важные пост , который говорить о fieldи propertyв Java и Котлин.
есть ли в Java что-то похожее на свойства C #?
https://blog.kotlin-academy.com/kotlin-programmer-dictionary-field-vs-property-30ab7ef70531

Поправьте меня, если я ошибаюсь. Надеюсь, это поможет


Спасибо, мне очень помогло!
marcode_ely

8

Getter в kotlin по умолчанию является общедоступным, но вы можете установить установщик как private и установить значение, используя один метод внутри класса. Как это.

/**
* Created by leo on 17/06/17.*/

package foo
class Person() {
var name: String = "defaultValue"
               private set

fun foo(bar: String) {
    name = bar // name can be set here
       }
}

fun main(args: Array<String>) {
  var p = Person()
  println("Name of the person is ${p.name}")
  p.foo("Jhon Doe")
  println("Name of the person is ${p.name}")
}

5

Вы можете увидеть это руководство для получения дополнительной информации:

Еще одно руководство по Kotlin для разработчиков Android

Свойства

В мире Kotlin классы не могут иметь полей, только свойства. Ключевое слово var сообщает нам, что свойство является изменяемым, в отличие от val. Посмотрим на пример:

class Contact(var number: String) {

   var firstName: String? = null
   var lastName: String? = null
   private val hasPrefix : Boolean
       get() = number.startsWith("+")

}

Кода немного, но за кулисами происходит много вещей. Мы рассмотрим это шаг за шагом. Прежде всего, мы создали общедоступный финальный класс Contact.

Это основное правило, с которым мы должны столкнуться: если не указано иное, классы по умолчанию являются общедоступными и окончательными (кстати, то же самое и для методов класса). Если вы хотите наследовать от класса, отметьте его ключевым словом open.


0

Вот практический, реальный пример получателя и установщика Kotlin (подробнее см. Здесь ):

// Custom Getter
val friendlyDescription get(): String {
    val isNeighborhood = district != null
    var description = if (isNeighborhood) "Neighborhood" else "City"
    description += " in"
    if (isNeighborhood) {
        description += " $city,"
    }
    province?.let {
        if (it.isNotEmpty()) {
            description += " $it,"
        }
    }
    description += " $country"
    return description
}

print(myLocation.friendlyDescription) // "Neighborhood in Denver, Colorado, United States"


// Custom Setter
enum class SearchResultType {
    HISTORY, SAVED, BASIC
}

private lateinit var resultTypeString: String

var resultType: SearchResultType
    get() {
        return enumValueOf(resultTypeString)
    }
    set(value) {
        resultTypeString = value.toString()
    }

result.resultType = SearchResultType.HISTORY
print(result.resultTypeString) // "HISTORY"

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.