Kotlin es un lenguaje de programación moderno que compila a bytecode Java. Es gratuito y de código abierto, y promete hacer que la codificación para Android sea aún más divertida.
En el artículo anterior, aprendiste sobre clases y objetos en Kotlin. En este tutorial, continuaremos aprendiendo más sobre las propiedades y también analizaremos los tipos avanzados de clases en Kotlin explorando lo siguiente:
Podemos declarar una propiedad no nula en Kotlin como inicializado tarde. Esto significa que una propiedad que no sea nula no se inicializará en el momento de la declaración con una inicialización de valor real no se producirá a través de ningún constructor, sino que, en cambio, se iniciará en forma tardía mediante un método o una inyección de dependencia.
Veamos un ejemplo para entender este modificador de propiedad único..
presentador de clase repositorio de var privado: ¿Repositorio? = null fun initRepository (repo: Repository): Unit this.repository = repo class Repository fun saveAmount (amount: Double)
En el código anterior, declaramos un nullable mutable. repositorio
propiedad que es de tipo Repositorio
-dentro de la clase Presentador
-y luego inicializamos esta propiedad a nula durante la declaración. Tenemos un metodo initRepository ()
en el Presentador
clase que reinicializa esta propiedad más tarde con un real Repositorio
ejemplo. Tenga en cuenta que a esta propiedad también se le puede asignar un valor mediante un inyector de dependencia como Dagger.
Ahora vamos a invocar métodos o propiedades en este repositorio
propiedad, tenemos que hacer una comprobación nula o utilizar el operador de llamada segura. ¿Por qué? Porque el repositorio
La propiedad es de tipo anulable (Repositorio?
). (Si necesita un repaso de nulability en Kotlin, por favor visite Nullability, Loops, and Conditions).
// Clase de presentador interno divertido guardar (cantidad: doble) repositorio? .SaveAmount (cantidad)
Para evitar tener que realizar verificaciones nulas cada vez que necesitamos invocar el método de una propiedad, podemos marcar esa propiedad con el a fines de
modificador: esto significa que hemos declarado esa propiedad (que es una instancia de otra clase) como inicializado tarde (lo que significa que la propiedad se inicializará más adelante).
presentador de clase repositorio de var de lateinit privado: Repositorio //…
Ahora, mientras esperemos hasta que la propiedad reciba un valor, estamos seguros de acceder a los métodos de la propiedad sin hacer ningún chequeo nulo. La inicialización de la propiedad puede ocurrir ya sea en un método de establecimiento o mediante inyección de dependencia..
repository.saveAmount (cantidad)
Tenga en cuenta que si intentamos acceder a los métodos de la propiedad antes de que se haya inicializado, obtendremos un kotlin.UninitializedPropertyAccessException
en vez de una Excepción de puntero nulo
. En este caso, el mensaje de excepción será "el repositorio de propiedades de lateinit no se ha inicializado".
Tenga en cuenta también las siguientes restricciones colocadas al retrasar la inicialización de una propiedad con a fines de
:
var
).En t
, Doble
, Flotador
, y así. En Funciones Avanzadas, introduje el en línea
modificador para funciones de orden superior: esto ayuda a optimizar cualquier función de orden superior que acepte un lambda como parámetro.
En Kotlin, también podemos usar este en línea
Modificador de propiedades. El uso de este modificador optimizará el acceso a la propiedad..
Veamos un ejemplo práctico..
clase Student val nickName: String get () println ("Nick name recuperado") return "koloCoder" fun main (args: Array) val student = Student () print (student.nickName)
En el código anterior, tenemos una propiedad normal., apodo
, eso no tiene el en línea
modificador Si descompilamos el fragmento de código, usando el Show Kotlin Bytecode característica (si está en IntelliJ IDEA o Android Studio, use Herramientas > Kotlin > Show Kotlin Bytecode), veremos el siguiente código de Java:
clase final pública Student @NotNull public String final getNickName () String var1 = "Nick nombre recuperado"; System.out.println (var1); devuelve "koloCoder"; clase final pública InlineFunctionKt public static final void main (@NotNull String [] args) Intrinsics.checkParameterIsNotNull (args, "args"); Estudiante estudiante = nuevo estudiante (); Cadena var2 = student.getNickName (); System.out.print (var2);
En el código Java generado anteriormente (algunos elementos del código generado se eliminaron por razones de brevedad), puede ver que dentro de la principal()
método el compilador creó una Estudiante
objeto, llamado el getNickName ()
Método, y luego imprimió su valor de retorno.
Ahora vamos a especificar la propiedad como en línea
en su lugar, y comparar el bytecode generado.
// ... inline val nickName: String // ...
Simplemente insertamos el en línea
modificador antes del modificador variable: var
o val
. Aquí está el código de bytes generado para esta propiedad en línea:
// ... public static final void main (@NotNull String [] args) Intrinsics.checkParameterIsNotNull (args, "args"); Estudiante estudiante = nuevo estudiante (); String var3 = "Nick nombre recuperado"; System.out.println (var3); String var2 = "koloCoder"; System.out.print (var2); //…
De nuevo, se eliminó algún código, pero la clave a tener en cuenta es la principal()
método. El compilador ha copiado la propiedad. obtener()
cuerpo de la función y lo pegó en el sitio de la llamada (este mecanismo es similar a las funciones en línea).
Nuestro código ha sido optimizado debido a que no es necesario crear un objeto y llamar al método de obtención de propiedades. Pero, como se explicó en la publicación de funciones en línea, tendríamos un bytecode más grande que antes, así que use con precaución.
Tenga en cuenta también que este mecanismo funcionará para las propiedades que no tienen un campo de respaldo (recuerde, un campo de respaldo es solo un campo que utilizan las propiedades cuando desea modificar o usar los datos de ese campo).
En Funciones avanzadas, también traté las funciones de extensión, que nos permiten extender una clase con una nueva funcionalidad sin tener que heredar de esa clase. Kotlin también proporciona un mecanismo similar para las propiedades, llamado propiedades de extensión.
val String.upperCaseFirstLetter: String get () = this.substring (0, 1) .toUpperCase (). plus (this.substring (1))
En la publicación de Funciones Avanzadas definimos un mayúsculas
función de extensión con tipo de receptor Cuerda
. Aquí, lo convertimos en una propiedad de extensión de nivel superior. Tenga en cuenta que tiene que definir un método getter en su propiedad para que esto funcione.
Entonces, con este nuevo conocimiento sobre las propiedades de extensión, sabrá que si alguna vez deseaba que una clase tuviera una propiedad que no estuviera disponible, es libre de crear una propiedad de extensión de esa clase..
Comencemos con una clase típica de Java o POJO (objeto Java antiguo simple).
clase pública BlogPost título privado final de la cadena; url final privado URI; Descripción de la cadena final privada; Fecha final privada publishDate; // ... constructor no incluido por motivos de brevedad @Override public boolean igual a (Object o) if (this == o) devuelve true; if (o == null || getClass ()! = o.getClass ()) devuelve false; BlogPost blogPost = (BlogPost) o; if (title! = null?! title.equals (blogPost.title): blogPost.title! = null) devuelve false; if (url! = null?! url.equals (blogPost.url): blogPost.url! = null) devuelve false; if (description! = null?! description.equals (blogPost.description): blogPost.description! = null) devuelve false; volver publishDate! = null? publishDate.equals (blogPost.publishDate): blogPost.publishDate == null; @Override public int hashCode () int result = title! = Null? title.hashCode (): 0; result = 31 * result + (url! = null? url.hashCode (): 0); result = 31 * result + (description! = null? description.hashCode (): 0); result = 31 * result + (publishDate! = null? publishDate.hashCode (): 0); resultado de retorno @Oversión pública String toString () return "BlogPost " + "title = '" + title +' \ "+", url = "+ url +", + description + "\" + ", publishDate =" + publishDate + ''; //… los setters y los getters también son ignorados por el bien de la brevedad
Como puede ver, debemos codificar explícitamente los accesores de propiedades de clase: el getter y el setter, así como código hash
, es igual a
, y Encadenar
métodos (aunque IntelliJ IDEA, Android Studio o la biblioteca AutoValue pueden ayudarnos a generarlos). Vemos este tipo de código repetitivo principalmente en la capa de datos de un proyecto típico de Java. (Quité los accesores de campo y el constructor por razones de brevedad).
Lo bueno es que el equipo de Kotlin nos proporcionó la datos
Modificador para las clases que eliminan la escritura de estas repeticiones..
Ahora escribamos el código anterior en Kotlin.
clase de datos BlogPost (var title: String, var url: URI, var description: String, var publishDate: Date)
¡Increíble! Simplemente especificamos el datos
modificador antes de la clase
palabra clave para crear una clase de datos, al igual que lo que hicimos en nuestro Entrada en el blog
Clase de Kotlin arriba Ahora el es igual a
, código hash
, Encadenar
, dupdo
, y para nosotros se crearán múltiples métodos de componentes. Tenga en cuenta que una clase de datos puede extender otras clases (esta es una nueva característica de Kotlin 1.1).
es igual a
MétodoEste método compara la igualdad de dos objetos, y devuelve verdadero si son iguales o falsos de lo contrario. En otras palabras, compara si las dos instancias de clase contienen los mismos datos.
student.equals (student3) // usando el == en Kotlin student == student3 // igual que usar equals ()
En Kotlin, utilizando el operador de igualdad. ==
llamará al es igual a
método detrás de las escenas.
código hash
Método Este método devuelve un valor entero utilizado para el almacenamiento rápido y la recuperación de datos almacenados en una estructura de datos de recopilación basada en hash, por ejemplo, en el HashMap
y HashSet
tipos de colección.
Encadenar
MétodoEste método devuelve un Cuerda
representación de un objeto.
clase de datos Person (var firstName: String, var lastName: String) val person = Person ("Chike", "Mgbemena") println (person) // print "Person (firstName = Chike, lastName = Mgbemena)"
Con solo llamar a la instancia de la clase, obtenemos un objeto de cadena que se nos devuelve: Kotlin llama al objeto Encadenar()
bajo el capó para nosotros. Pero si no ponemos el datos
palabra clave en, vea lo que nuestra representación de cadena de objeto sería:
com.chike.kotlin.classes.Person@2f0e140b
Mucho menos informativo!
dupdo
MétodoEste método nos permite crear una nueva instancia de un objeto con todos los mismos valores de propiedad. En otras palabras, crea una copia del objeto..
val person1 = Persona ("Chike", "Mgbemena") println (person1) // Persona (firstName = Chike, lastName = Mgbemena) val person2 = person1.copy () println (person2) // Person (firstName = Chike, lastName = Mgbemena)
Una cosa genial sobre el dupdo
El método en Kotlin es la capacidad de cambiar propiedades durante la copia..
val person3 = person1.copy (lastName = "Onu") println (person3) // Person3 (firstName = Chike, lastName = Onu)
Si eres un codificador de Java, este método es similar al clon()
método con el que ya estás familiarizado. Pero el Kotlin dupdo
El método tiene características más potentes..
En el Persona
clase, también tenemos dos métodos auto-generados para nosotros por el compilador debido a la datos
palabra clave colocada en la clase. Estos dos métodos tienen el prefijo "componente" y luego un sufijo numérico: componente1 ()
, componente2 ()
. Cada uno de estos métodos representa las propiedades individuales del tipo. Tenga en cuenta que el sufijo corresponde al orden de las propiedades declaradas en el constructor primario.
Así, en nuestro ejemplo llamando componente1 ()
devolverá el primer nombre, y llamando componente2 ()
devolverá el apellido.
println (person3.component1 ()) // Chike println (person3.component2 ()) // Onu
Sin embargo, es difícil comprender y leer llamar a las propiedades usando este estilo, por lo que llamar al nombre de la propiedad de manera explícita es mucho mejor. Sin embargo, estas propiedades creadas implícitamente tienen un propósito muy útil: nos permiten hacer una declaración de desestructuración, en la que podemos asignar cada componente a una variable local..
val (firstName, lastName) = Person ("Angelina", "Jolie") println (firstName + "" + lastName) // Angelina Jolie
Lo que hemos hecho aquí es asignar directamente la primera y la segunda propiedades (nombre de pila
y apellido
) del Persona
escriba a las variables nombre de pila
y apellido
respectivamente. También discutí este mecanismo conocido como declaración de desestructuración en la última sección de los paquetes y funciones básicas post.
En la publicación Más diversión con funciones, te dije que Kotlin tiene soporte para funciones locales o anidadas, una función que se declara dentro de otra función. Bueno, Kotlin también admite clases anidadas, una clase creada dentro de otra clase.
clase OuterClass clase NestedClass fun nestedClassFunc ()
Incluso llamamos a las funciones públicas de la clase anidada como se ve a continuación: una clase anidada en Kotlin es equivalente a una estático
Clase anidada en Java. Tenga en cuenta que las clases anidadas no pueden almacenar una referencia a su clase externa.
val nestedClass = OuterClass.NestedClass () nestedClass.nestedClassFunc ()
También somos libres de establecer la clase anidada como privada; esto significa que solo podemos crear una instancia de Clase anidada
dentro del alcance de la Clase externa
.
Las clases internas, por otro lado, pueden hacer referencia a la clase externa en la que se declaró. Para crear una clase interna, colocamos la interior
palabra clave antes de la clase
palabra clave en una clase anidada.
clase OuterClass () val oCPropt: String = "Yo" clase interna InnerClass fun innerClassFunc () val outerClass = this @ OuterClass print (outerClass.oCPropt) // imprime "Yo"
Aquí hacemos referencia a la Clase externa
desde el Clase interna
mediante el uso esta @ clase externa
.
Un tipo de enumeración declara un conjunto de constantes representadas por identificadores. Este tipo especial de clase es creado por la palabra clave enumerar
que se especifica antes de la clase
palabra clave.
clase de enumeración País NIGERIA, GHANA, CANADA
Para recuperar un valor de enumeración basado en su nombre (al igual que en Java), hacemos esto:
Country.valueOf ("NIGERIA")
O podemos usar el Kotlin enumValueOf
Método auxiliar para acceder a las constantes de forma genérica:
enumValueOf("NIGERIA")
Además, podemos obtener todos los valores (como para una enumeración de Java) de esta manera:
País.valores ()
Finalmente, podemos utilizar el Kotlin. enumValues
Método auxiliar para obtener todas las entradas de enumeración de forma genérica:
enumValues()
Esto devuelve una matriz que contiene las entradas de enumeración.
Al igual que una clase normal, la enumerar
El tipo puede tener su propio constructor con propiedades asociadas a cada constante de enumeración.
enum class Country (val callingCode: Int) NIGERIA (234), USA (1), GHANA (233)
En el País
constructor primario tipo enum, definimos la propiedad inmutable códigos de llamada
para cada enumeración constante. En cada una de las constantes, pasamos un argumento al constructor..
Entonces podemos acceder a la propiedad de constantes como esta:
val country = Country.NIGERIA print (country.callingCode) // 234
Una clase sellada en Kotlin es una clase abstracta (nunca pretendes crear objetos a partir de ella) que otras clases puedan extender. Estas subclases se definen dentro del cuerpo de la clase sellada en el mismo archivo. Debido a que todas estas subclases están definidas dentro del cuerpo de la clase sellada, podemos conocer todas las subclases posibles simplemente viendo el archivo.
Veamos un ejemplo práctico..
// clase de shape.kt clase de forma Círculo: clase de Shape () triángulo: clase de Shape () rectángulo: Shape ()
Para declarar una clase como sellada, insertamos el sellado
modificador antes de la clase
modificador en el encabezado de la declaración de clase, en nuestro caso, declaramos el Forma
clase como sellado
. Una clase sellada está incompleta sin sus subclases, como una clase abstracta típica, así que tenemos que declarar las subclases individuales dentro del mismo archivo (forma.kt en este caso). Tenga en cuenta que no puede definir una subclase de una clase sellada de otro archivo.
En nuestro código anterior, hemos especificado que el Forma
La clase puede ser extendida solo por las clases. Circulo
, Triángulo
, y Rectángulo
.
Las clases selladas en Kotlin tienen las siguientes reglas adicionales:
resumen
a una clase sellada, pero esto es redundante porque las clases selladas son abstractas por defecto.abierto
o final
modificador. Las clases que extienden subclases de una clase sellada pueden ubicarse en el mismo archivo o en otro archivo. La subclase de clase sellada debe estar marcada con la abierto
modificador (aprenderá más sobre la herencia en Kotlin en la próxima publicación).
// employee.kt clase sellada Empleado clase abierta Artista: Employee () // musician.kt clase Músico: Artista ()
Una clase sellada y sus subclases son realmente útiles en un cuando
expresión. Por ejemplo:
fun whatIsIt (shape: Shape) = when (shape) is Circle -> println ("A circle") es Triangle -> println ("A triangle") is Rectangle -> println ("A rectangle")
Aquí el compilador es inteligente para asegurarnos de cubrir todos los posibles cuando
casos. Eso significa que no hay necesidad de agregar el más
cláusula.
Si tuviéramos que hacer lo siguiente:
fun whatIsIt (shape: Shape) = when (shape) is Circle -> println ("A circle") es Triangle -> println ("A triangle")
El código no se compilaría, porque no hemos incluido todos los casos posibles. Tendríamos el siguiente error:
Kotlin: 'cuando' la expresión debe ser exhaustiva, agregue necesario 'es una rama' Rectangle 'o' else 'en su lugar.
Así que podríamos incluir el es rectángulo
caso o incluir el más
cláusula para completar el cuando
expresión.
En este tutorial, aprendiste más sobre las clases en Kotlin. Cubrimos lo siguiente sobre las propiedades de clase:
Además, aprendió sobre algunas clases geniales y avanzadas, como clases de datos, enumeración, anidadas y selladas. En el siguiente tutorial de la serie Kotlin From Scratch, se le presentarán las interfaces y la herencia en Kotlin. Te veo pronto!
Para obtener más información sobre el idioma Kotlin, recomiendo visitar la documentación de Kotlin. O echa un vistazo a algunas de nuestras otras publicaciones de desarrollo de aplicaciones para Android aquí en Envato Tuts!