
Generics in Kotlin
📌 Generics in Kotlin
Generics in Kotlin provide a way to create classes, interfaces, and functions that can operate with different data types using type parameters. It allows for code reusability and ensures type safety during compile time.
✅ 1. Basic Syntax of Generics
In Kotlin, generics are defined using angle brackets (<>
) with a type parameter.
📌 Syntax:
class Box<T>(val item: T) { fun (): T { return item }}fun () { val intBox = Box(10) val stringBox = Box("Hello, Kotlin!") println(intBox.getItem()) // Output: 10 println(stringBox.getItem()) // Output: Hello, Kotlin!}
Box<T>
can store any type likeInt
orString
.
✅ 3. Generic Function
You can create functions that accept generic parameters using <T>
.
📌 Example:
fun (data: fun () { printData(100) // Output: Data: 100 printData("Kotlin") // Output: Data: Kotlin printData(25.5) // Output: Data: 25.5}
<T>
declares a generic type parameter for the function.
✅ 4. Multiple Type Parameters
You can use multiple type parameters like <T, U>
.
📌 Example:
class PairData<T, U>(val first: T, val second: U) { fun () { println("First: $first, Second: fun () { val pair = PairData("Age", 30) pair.display() // Output: First: Age, Second: 30}
T
andU
can hold different types.
✅ 5. Generic Constraints
You can restrict generic types using constraints with the :
keyword.
📌 Example:
fun (value: T): fun () { println(square(4)) // Output: 16.0 println(square(5.5)) // Output: 30.25 // square("Kotlin") // Error: Type mismatch}
<T : Number>
restrictsT
to only accept Number types likeInt
,Float
, orDouble
.
✅ 6. Covariance (out
)
Use
out
when a class produces data (T
can only be returned).It is read-only.
📌 Example:
class Producer<out T>(private val data: T) { fun (): T = data}fun () { val producer: Producer<String> = Producer("Kotlin") println(producer.getData()) // Output: Kotlin}
out
is used to ensure type safety when returning values.
✅ 7. Contravariance (in
)
Use
in
when a class consumes data (T
can only be used as a parameter).It is write-only.
📌 Example:
class Consumer<in T> { fun (data: fun () { val consumer: Consumer<Number> = Consumer() consumer.printData(42) // Output: Data: 42 consumer.printData(3.14) // Output: Data: 3.14}
in
is used for type flexibility when consuming values.
✅ 8. Generic Extension Functions
You can create generic extension functions that work on multiple data types.
📌 Example:
fun () { println("Type: ${this::class.simpleName}, Value: fun main() { 10.showType() // Output: Type: Int, Value: 10 "Kotlin".showType() // Output: Type: String, Value: Kotlin}
this
refers to the calling object.
✅ Conclusion
Generics increase code reusability and ensure type safety.
Use
<T>
for defining generic classes and functions.Apply constraints using
: ClassName
for type restrictions.Use
out
for covariance when returning data.Use
in
for contravariance when accepting data.Create flexible and reusable code using generics.