Diferencia entre una clase y un objeto en Kotlin

98

Soy nuevo en Kotlin y recientemente he convertido un archivo simple de Java a Kotlin. Me pregunto por qué el convertidor de Android cambió mi clase java a un objeto Kotlin.

Java:

public class MyClass {
    static public int GenerateChecksumCrc16(byte bytes[]) {

        int crc = 0xFFFF;
        int temp;
        int crc_byte;

        for (byte aByte : bytes) {

            crc_byte = aByte;

            for (int bit_index = 0; bit_index < 8; bit_index++) {

                temp = ((crc >> 15)) ^ ((crc_byte >> 7));

                crc <<= 1;
                crc &= 0xFFFF;

                if (temp > 0) {
                    crc ^= 0x1021;
                    crc &= 0xFFFF;
                }

                crc_byte <<= 1;
                crc_byte &= 0xFF;

            }
        }

        return crc;
    }
}

Kotlin convertido:

object MyClass {
    fun GenerateChecksumCrc16(bytes: ByteArray): Int {

        var crc = 0xFFFF
        var temp: Int
        var crc_byte: Int

        for (aByte in bytes) {

            crc_byte = aByte.toInt()

            for (bit_index in 0..7) {

                temp = crc shr 15 xor (crc_byte shr 7)

                crc = crc shl 1
                crc = crc and 0xFFFF

                if (temp > 0) {
                    crc = crc xor 0x1021
                    crc = crc and 0xFFFF
                }

                crc_byte = crc_byte shl 1
                crc_byte = crc_byte and 0xFF

            }
        }

        return crc
    }
}

¿Por qué no fue así?

class MyClass {
    ... etc ...
}

Cualquier ayuda sería muy apreciada, gracias.

Crujiente234
fuente

Respuestas:

96

Un objeto de Kotlin es como una clase de la que no se puede crear una instancia, por lo que se debe llamar por su nombre. (una clase estática per se)

El convertidor de Android vio que su clase contenía solo un método estático, por lo que lo convirtió en un objeto Kotlin.

Lea más sobre esto aquí: http://petersommerhoff.com/dev/kotlin/kotlin-for-java-devs/#objects

Titular
fuente
164

La documentación de Kotlin sobre esto es bastante buena, así que no dudes en leerla.

La respuesta elegida para esta pregunta tiene una fraseología pobre en su explicación y podría engañar fácilmente a la gente. Por ejemplo, un objeto no es "una clase estática per se", sino que lo es a static instance of a class that there is only one of, también conocido como singleton.

Quizás la mejor manera de mostrar la diferencia es mirar el código Kotlin descompilado en formato Java.

Objeto y clase de Kotlin:

object ExampleObject {
  fun example() {
  }
}

class ExampleClass {
  fun example() {
  }
}

Para usar el ExampleClass, necesitas crear una instancia de él:, ExampleClass().example()pero con un objeto, Kotlin crea una sola instancia de él para ti, y nunca llamas a su constructor, en su lugar, solo accedes a su instancia estática usando el nombre de: ExampleObject.example().

El código Java equivalente que generaría Kotlin:

Kotlin compila en código de bytes de Java, pero si revertimos la compilación del código de Kotlin compilado anteriormente en código de Java, esto es lo que obtenemos:

public final class ExampleObject {
   public static final ExampleObject INSTANCE = new ExampleObject();

   private ExampleObject() { }

   public final void example() {
   }
}

public final class ExampleClass {
   public final void example() {
   }
}

Usaría el objeto en Kotlin de la siguiente manera:

ExampleObject.example()

Que se compilaría en el código de bytes de Java equivalente para:

ExampleObject.INSTANCE.example()

¿Por qué Kotlin presenta objects?

El caso de uso principal de objecten Kotlin es porque Kotlin intenta eliminar los estáticos y los primitivos, dejándonos con un lenguaje puramente orientado a objetos. Kotlin todavía usa staticy primitivos debajo del capó, pero desalienta a los desarrolladores a usar esos conceptos más. En cambio, ahora Kotlin reemplaza instancias de objetos estáticos con singleton. Donde antes usaba un campo estático en Java, en Kotlin ahora creará un objecty pondrá ese campo en el object.

Interoperabilidad con Java:

Debido a que Kotlin es 100% interoperable con Java, a veces querrá exponer ciertas API o campos de una manera que sea más agradable de leer para Java. Para hacer esto, puede usar la @JvmStaticanotación. Al anotar un campo o una función en un objectcon @JvmStatic, se compilará en campos estáticos que Java puede usar más fácilmente.

Objetos complementarios:

Una última cosa que vale la pena mencionar es la companion objects. En Java, normalmente tiene clases que tienen contenido estático, pero también contenido no estático / de instancia. Kotlin le permite hacer algo similar con los objetos complementarios, que están objectvinculados a a class, lo que significa que una clase puede acceder a las funciones y propiedades privadas de su objeto complementario:

class ExampleClass {
  companion object {
    // Things that would be static in Java would go here in Kotlin
    private const val str = "asdf"
  }

  fun example() {
    // I can access private variables in my companion object
    println(str)
  }
}
spierce7
fuente
6
Buena explicación. Muchas gracias.
Danish Ansari
12

Un objeto es un singleton. No es necesario crear una instancia para usarlo.

Es necesario crear una instancia de una clase para poder usarla

De la misma manera que en Java puede decir Math.sqrt (2) y no necesita crear una instancia de Math para usar sqrt, en Kotlin puede crear un objeto para contener estos métodos, y son efectivamente estáticos.

Hay algo de información aquí:

https://kotlinlang.org/docs/reference/object-declarations.html

IntelliJ obviamente ha sido lo suficientemente inteligente como para detectar que necesita un objeto, ya que solo tiene métodos estáticos de Java.

Bruce Lowe
fuente
Espera, pero si mi clase Humantiene un campo int estático Population, ¿cómo se vería eso en Kotlin? companion object { @JvmField val Population; }¿o algo?
Squirrelkiller
3

También puede definir funciones sin declaración de objeto. Solo en archivo .kt Por ejemplo:

fun GenerateChecksumCrc16(bytes: ByteArray): Int {
    ...
}

Y esta función estaba relacionada con el paquete donde se declara el archivo .kt. Puede leer más sobre esto aquí https://kotlinlang.org/docs/reference/packages.html

Silvestr
fuente
1

Basándose en la respuesta de @ speirce7:

El siguiente código muestra la diferencia básica entre una clase y un objeto cuando se trata de Kotlin:

class ExampleClass(){
    fun example(){
            println("I am in the class.")
    }
}

object ExampleObject{
    fun example(){
            println("I am in the object.")
    }
}

fun main(args: Array<String>){
    val exampleClass = ExampleClass() // A class needs to be instantiated.
    exampleClass.example()            // Running the instance of the object.
    ExampleObject.example()           // An object can be thought of as a Singleton and doesn't need any instantiation.
}
Raj
fuente