Getters e setters em Kotlin

86

Em Java, por exemplo, posso escrever getters sozinho (gerado pelo IDE) ou usar anotações como @Getter em lombok - o que era muito simples.

No entanto, Kotlin tem getters e setters por padrão . Mas não consigo entender como usá-los.

Eu quero fazer isso, digamos - semelhante ao Java:

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

Então, como funcionam os getters?

nutella_eater
fonte

Respostas:

142

Getters e setters são gerados automaticamente em Kotlin. Se você escrever:

val isEmpty: Boolean

É igual ao seguinte código Java:

private final Boolean isEmpty;

public Boolean isEmpty() {
    return isEmpty;
}

No seu caso, o modificador de acesso privado é redundante - isEmpty é privado por padrão e pode ser acessado apenas por um getter. Ao tentar obter a propriedade isEmpty do seu objeto, você chama o método get em real. Para entender melhor os getters / setters em Kotlin: os dois exemplos de código abaixo são iguais:

var someProperty: String = "defaultValue"

e

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

Também quero salientar que thisem um getter não é sua propriedade - é a instância da classe. Se você deseja obter acesso ao valor do campo em um getter ou setter, pode usar a palavra reservada fieldpara ele:

val isEmpty: Boolean
  get() = field

Se você deseja apenas ter um método get em acesso público - você pode escrever este código:

var isEmpty: Boolean
    private set 

devido ao modificador privado próximo ao acessador set, você pode definir este valor apenas em métodos dentro do seu objeto.

Cortwave
fonte
16
In your case the private access modifier is redundantComo? O documento do Kotlin diz que o modificador padrão é público. kotlinlang.org/docs/reference/visibility-modifiers.html
@Nada, sim, parece um campo público, mas por dentro você chama o método getter
Cortwave
O val isEmpty: Booleannão irá compilar porque isEmpty ainda não foi inicializado, certo? Estou começando a aprender Kotlin. Além disso, com o que está acontecendo get() = field?
Shubham A.
1
@Chiara valnão tem setter
chroder
@croder sim, você está certo, devo ter lido errado ... comentário excluído. Obrigado por apontar isso
Chiara
30

As regras sobre os modificadores de visibilidade dos acessadores de propriedade são as seguintes:

  • Visibilidade Getter de vare valpropriedade deve ser exatamente o mesmo para a visibilidade da propriedade, assim você pode duplicar única explicitamente o modificador de propriedade, mas é redundante:

    protected val x: Int
        protected get() = 0 // No need in `protected` here.
    
  • A visibilidade do setter da varpropriedade deve ser a mesma ou menos permissiva do que a visibilidade da propriedade:

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

No Kotlin, as propriedades são sempre acessadas por meio de getter e setter, portanto, não há necessidade de criar uma propriedade privatecom publicacessadores como em Java - seu campo de apoio (se presente) já é privado. Portanto, os modificadores de visibilidade nos acessadores de propriedade são usados ​​apenas para tornar a visibilidade do setter menos permissiva:

  • Para uma propriedade com campo de apoio e acessadores padrão:

    var x = 0 // `public` by default
        private set
    
  • Para uma propriedade sem campo de apoio:

    var x: Int // `public` by default
        get() = 0
        protected set(value: Int) { }
    
tecla de atalho
fonte
É possível definir e obter tipos diferentes? Definindo x igual a algum "Some String"e retornando digamos o comprimento 11,, da string?
Carel
@Carel, não, a partir de agora, este caso de uso não é suportado: os acessadores de uma propriedade devem operar exatamente com o tipo da propriedade. O uso de um tipo diferente é abordado com o uso de uma propriedade de apoio separada
tecla de atalho
Droga, Kotlin é tão próximo do Python que você acha que só funcionará quando for lembrado de que está digitado ... e cortar sua própria garganta.
Carel
Obrigado por modificadores de acesso. Removi privatede uma variável e ela se tornou acessível em outra classe com getter.
CoolMind
Recebo uma mensagem "Setters privados não são permitidos para propriedades abertas" ao usar a combinação "var x // conjunto privado". Resolvido declarando como "final var x"
Tom,
14

1) Exemplo padrão settere getterpara propriedade firstName em Kotlin

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

}

Usando

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

SE o seu setterou getterfor exatamente o mesmo acima, você pode removê-lo porque é desnecessário

2) Exemplo de setter e getter personalizados.

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")
            }
        }
}

Usando

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

Mais
eu começo a aprender Kotlin com Java, então estou confuso sobre fielde propertyporque em Java não existe property.
Depois de alguma pesquisa, vejo fielde propertyno Kotlin parece C # ( qual é a diferença entre um campo e uma propriedade? )

Aqui estão algumas postagens relevantes que falam sobre fielde propertyem Java e Kotlin.
java tem algo semelhante às propriedades do C #?
https://blog.kotlin-academy.com/kotlin-programmer-dictionary-field-vs-property-30ab7ef70531

Corrija-me se eu estiver errado. Espero que ajude

Phan Van Linh
fonte
Obrigado, realmente me ajudou!
marcode_ely
8

Getter no kotlin é por padrão público, mas você pode definir o setter como privado e definir o valor usando um método dentro de uma classe. Como isso.

/**
* 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}")
}
Lalit Behera
fonte
5

Você pode ver este tutorial para mais informações:

Mais um tutorial do Kotlin para desenvolvedores Android

Propriedades

No mundo Kotlin, as classes não podem ter campos, apenas propriedades. A palavra-chave var nos diz que a propriedade é mutável, em contraste com val. Vamos ver um exemplo:

class Contact(var number: String) {

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

}

Não há muito código, mas muitas coisas estão acontecendo nos bastidores. Vamos passar por isso passo a passo. Em primeiro lugar, criamos um contato público final da classe.

Esta é a regra primária que temos que enfrentar: se não for especificado de outra forma, as classes são públicas e finais por padrão (a propósito, o mesmo é para métodos de classe). Se você deseja herdar de classe, marque-o com a palavra-chave open.

Plutão 65
fonte
0

Aqui está um exemplo prático e real de um getter e setter Kotlin (veja mais detalhes aqui ):

// 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"

Ricky Padilla
fonte