Classe Any

Come già accennato nella lezione 2 in Kotlin ogni classe, in maniera implicita o meno estende la classe Any. Le due sintassi sono uguali:

class Employee : Any()

class Employee

Esplicitando o meno l'ereditarietà tramite : Any() il risultato non cambia. La classe Any offre alcuni metodi targati con la keyword open:

equals() open operator fun equals(other: Any?): Boolean
hashCode() open fun hashCode(): Int
toString() open fun toString(): String

Per esempio in una classe per contenere il numero di telefono ha senso che il metodo toString() restituisce il numero di telefono nella forma (xxx) xxx-xxxx. Come che il metodo equals() esegua un confronto fra due istanze e non tra i due riferimenti. Guardiamo la seguente classe per capire l'utilità:

class PhoneNumber(areaCode: Int, exchange: Int, extension: Int) {

private val areaCode: Short

private val exchange: Short

private val extension: Short

init {

rangeCheck(areaCode, 999, "area code")

rangeCheck(exchange, 999, "exchange")

rangeCheck(extension, 9999, "extension")

this.areaCode = areaCode.toShort()

this.exchange = exchange.toShort()

this.extension = extension.toShort()

}

private fun rangeCheck(arg: Int, max: Int, name: String) {

if (arg < 0 || arg > max)

throw IllegalArgumentException(name + ": " + arg)

}

override fun equals(other: Any?): Boolean {

if (this === other) return true

if (other?.javaClass != javaClass) return false

other as PhoneNumber

if (areaCode != other.areaCode) return false

if (exchange != other.exchange) return false

if (extension != other.extension) return false

return true

}

override fun hashCode(): Int {

var result: Int = areaCode.toInt()

result = 31 * result + exchange

result = 31 * result + extension

return result

}

override fun toString(): String {

return "($areaCode) $exchange-$extension"

}

}

data class

Kotlin, per ovviare alla mancanza di strutture dati utili alla memorizzazione di dati nella JVM (per esempio le struct del C# o Swift) ha introdotto le data class:

Una data class in Kotlin:

data class Person(val name: String, val email: String, val age: Int)

Fine, basta aggiungere la parola chiave data alla dichiarazione della classe.

Vediamo cosa succede quando richiamiamo la classe:

fun main(args: Array) {

val person: Person = Person("matteo", "[email protected]", 28)

println(person.name)

println(person.toString())

}

Abbiamo anche richiamato il metodo toString(), senza farne l'override, con questo bel risultato:

matteo Person(name=matteo, [email protected], age=28)

Ma senza la parola data e rilanciare il main otteniamo:

matteo

com.kotlin.test.Person@610455d6

Come vedete il risultato è completamente diverso. In nelle data class c'è l'override automatico per il metodo toString() (e non solo!). Ovviamente possiamo fare molto di più con queste classi:

  • Impostare alcuni campi come mutabili ed altri no:

data class Person(var name: String, var email: String, val dateOfBorn : Date)

  • Copiare l'oggetto in nuovo oggetto (le data class di Kotlin ci permettono di realizzare delle copie dell'istanza tramite la funzione copy()). Kotlin implementa la funzione copy() nel seguente modo:

fun copy(name: String = this.name, email: String = this.email, age: Int = this.age) = Person(name, email, age)

  • Ricordo che nessuno ci impedisce di modificare la funzione copy(). Fatto sta che un tipico utilizzo è il seguente:

val jack = User(name = "Jack", email = [email protected], age = 1)

val olderJack = jack.copy(age = 2)

  • Realizzare costruttuti secondari, sempre con questo formalismo: constructor(name: String, age: Int) : this(name)
  • Destrutturare l'oggetto (non preoccupatevi dalle cose strane, le vedremo in una prossima lezione)

val jane = Person("Jane", "[email protected]", 35)

val (name, email, age) = jane

println("$name, $age years of age") // prints "Jane, 35 years of age"

Le data class di Kotlin offrono le seugenti agevolazioni implicite:

ovverride automatico dei metodi della classe Any: toString(), hashCode() e equals();

  • generazione automatica del metodo copy();
  • generazione automatica dei metodi per destrutturare l'oggetto: component1(), component2(), ..., componentN();

Nota: Le data class ci obbligano a specificare se il campo è una val o una var, inoltre il costruttore primario richiede almeno un parametro e la classe non estendere altre classi (ma può implementare interfacce ) e non può essere avere i seguenti modificatori: open, abstract, sealed o inner.

results matching ""

    No results matching ""