In Kotlin, everything is an object in the sense that you can call member functions and properties on any variable.
Some types can have a special internal representation – for example, numbers, characters and booleans can be represented as primitive values at runtime – but to the user they look like ordinary classes.
Byte - 8 bits
Short - 16 bits
Int - 32 bits
Long - 64 bits
Compiler automatically infer the type of numbers.
Or you can specify Long type with suffix L.
val one = 1 // Int
val threeBillion = 3000000000 // Long
val oneLong = 1L // Long
val oneByte: Byte = 1
IEEE 754 standard.
Float - 32 bits, signle precision, decimal digits 6-7
Double - 64 bits, double precision, decimal digits 15-16
Fractional part is needed.
For variables initialized with fractional numbers, the compiler infers the Double type
val pi = 3.14 // Double
// val one: Double = 1 // Error: type mismatch
val oneDouble = 1.0 // Double
To explicitly specify the Float type for a value, add the suffix f or F. If such a value contains more than 6-7 decimal digits, it will be rounded
val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float, actual value is 2.7182817
Decimals: 123
Longs are tagged by a capital L: 123L
Hexadecimals: 0x0F
Binaries: 0b00001011
Doubles by default: 123.5, 123.5e10
Floats are tagged by f or F: 123.5f
you can use underscore to make more readable.
val oneMillion = 1_000_000
On the JVM platform, numbers are stored as primitive types: int, double, and so on. Exceptions are cases when you create a nullable number reference such as Int? or use generics.
Nullable references to the same number can refer to different objects:
val a: Int = 100
val boxedA: Int? = a
val anotherBoxedA: Int? = a
val b: Int = 10000
val boxedB: Int? = b
val anotherBoxedB: Int? = b
println(boxedA === anotherBoxedA) // true
println(boxedB === anotherBoxedB) // false
Due to different representations, smaller types are not subtypes of bigger ones.
If they were, we would have troubles of the following sort
// Hypothetical code, does not actually compile:
val a: Int? = 1 // A boxed Int (java.lang.Integer)
val b: Long? = a // Implicit conversion yields a boxed Long (java.lang.Long)
print(b == a) // Surprise! This prints "false" as Long's equals() checks whether the other is Long as well
As a consequence, smaller types are NOT implicitly converted to bigger types. This means that assigning a value of type Byte to an Int variable requires an explicit conversion
val b: Byte = 1 // OK, literals are checked statically
// val i: Int = b // ERROR
val i1: Int = b.toInt()
toByte()
toShort()
toInt()
toLong()
toFloat()
toDouble()
In many cases, there is no need for explicit conversions because the type is inferred from the context.
+, -, , /,
You can override these for custom classes.
always returns an integer number. Any fractional part is discarded.
To return a floating-point type, explicitly convert one of the arguments to a floating-point type.
val x = 5 / 2
//println(x == 2.5) // ERROR: Operator '==' cannot be applied to 'Int' and 'Double'
println(x == 2)
val x = 5 / 2.toDouble()
println(x == 2.5)
shl(bits) – signed shift left
shr(bits) – signed shift right
ushr(bits) – unsigned shift right
and(bits) – bitwise AND
or(bits) – bitwise OR
xor(bits) – bitwise XOR
inv() – bitwise inversion