Skip to Content
Kotlin📘 Ngôn ngữ KotlinOperator Overloading

Operator Overloading trong Kotlin

1. Giới thiệu

Kotlin cho phép overload các operators (toán tử) cho các kiểu dữ liệu tự định nghĩa. Điều này cho phép sử dụng cú pháp tự nhiên như a + b, a[i], a in collection với các class của bạn.

2. Arithmetic Operators

Plus, Minus, Times, Div, Rem

ExpressionFunction name
a + ba.plus(b)
a - ba.minus(b)
a * ba.times(b)
a / ba.div(b)
a % ba.rem(b)
data class Point(val x: Int, val y: Int) { operator fun plus(other: Point) = Point(x + other.x, y + other.y) operator fun minus(other: Point) = Point(x - other.x, y - other.y) operator fun times(scale: Int) = Point(x * scale, y * scale) } fun main() { val p1 = Point(10, 20) val p2 = Point(5, 10) println(p1 + p2) // Point(x=15, y=30) println(p1 - p2) // Point(x=5, y=10) println(p1 * 3) // Point(x=30, y=60) }

Unary Operators

ExpressionFunction name
+aa.unaryPlus()
-aa.unaryMinus()
!aa.not()
++a, a++a.inc()
--a, a--a.dec()
data class Counter(val value: Int) { operator fun unaryMinus() = Counter(-value) operator fun inc() = Counter(value + 1) operator fun dec() = Counter(value - 1) } fun main() { var counter = Counter(5) println(-counter) // Counter(value=-5) println(++counter) // Counter(value=6) println(--counter) // Counter(value=5) }

3. Compound Assignment Operators

ExpressionFunction name
a += ba.plusAssign(b)
a -= ba.minusAssign(b)
a *= ba.timesAssign(b)
a /= ba.divAssign(b)
class MutablePoint(var x: Int, var y: Int) { operator fun plusAssign(other: MutablePoint) { x += other.x y += other.y } } fun main() { val point = MutablePoint(10, 20) point += MutablePoint(5, 5) println("(${point.x}, ${point.y})") // (15, 25) }

Lưu ý: Nếu định nghĩa cả plusplusAssign, Kotlin sẽ ưu tiên plusAssign cho += với var.

4. Comparison Operators

equals (==, !=)

data class Person(val name: String, val age: Int) { override fun equals(other: Any?): Boolean { if (other !is Person) return false return name == other.name && age == other.age } override fun hashCode() = name.hashCode() * 31 + age } fun main() { val p1 = Person("Alice", 30) val p2 = Person("Alice", 30) val p3 = Person("Bob", 25) println(p1 == p2) // true println(p1 == p3) // false println(p1 != p3) // true }

Note: data class tự động generate equals()hashCode().

compareTo (<, >, <=, >=)

ExpressionFunction call
a > ba.compareTo(b) > 0
a < ba.compareTo(b) < 0
a >= ba.compareTo(b) >= 0
a <= ba.compareTo(b) <= 0
data class Version(val major: Int, val minor: Int, val patch: Int) : Comparable<Version> { override fun compareTo(other: Version): Int { return when { major != other.major -> major - other.major minor != other.minor -> minor - other.minor else -> patch - other.patch } } } fun main() { val v1 = Version(1, 0, 0) val v2 = Version(2, 0, 0) val v3 = Version(1, 5, 0) println(v1 < v2) // true println(v3 > v1) // true println(v1 <= v1) // true }

5. Indexed Access Operators

get và set

ExpressionFunction call
a[i]a.get(i)
a[i, j]a.get(i, j)
a[i] = ba.set(i, b)
a[i, j] = ba.set(i, j, b)
class Matrix(private val rows: Int, private val cols: Int) { private val data = Array(rows) { IntArray(cols) } operator fun get(row: Int, col: Int): Int { return data[row][col] } operator fun set(row: Int, col: Int, value: Int) { data[row][col] = value } } fun main() { val matrix = Matrix(3, 3) matrix[0, 0] = 1 matrix[1, 1] = 5 matrix[2, 2] = 9 println(matrix[0, 0]) // 1 println(matrix[1, 1]) // 5 }

Ví dụ với Map-like class

class MutableProperties { private val map = mutableMapOf<String, Any?>() operator fun get(key: String): Any? = map[key] operator fun set(key: String, value: Any?) { map[key] = value } } fun main() { val props = MutableProperties() props["name"] = "Alice" props["age"] = 30 println(props["name"]) // Alice println(props["age"]) // 30 }

6. in Operator (contains)

ExpressionFunction call
a in bb.contains(a)
a !in b!b.contains(a)
data class Rectangle(val x: Int, val y: Int, val width: Int, val height: Int) { operator fun contains(point: Point): Boolean { return point.x in x until (x + width) && point.y in y until (y + height) } } data class Point(val x: Int, val y: Int) fun main() { val rect = Rectangle(0, 0, 100, 100) val p1 = Point(50, 50) val p2 = Point(150, 50) println(p1 in rect) // true println(p2 in rect) // false println(p2 !in rect) // true }

7. Range Operators

rangeTo (..)

ExpressionFunction call
a..ba.rangeTo(b)
a..<ba.rangeUntil(b)
data class Date(val year: Int, val month: Int, val day: Int) : Comparable<Date> { override fun compareTo(other: Date): Int { return compareValuesBy(this, other, Date::year, Date::month, Date::day) } operator fun rangeTo(other: Date) = DateRange(this, other) } class DateRange( override val start: Date, override val endInclusive: Date ) : ClosedRange<Date>, Iterable<Date> { override fun iterator(): Iterator<Date> = DateIterator(start, endInclusive) } class DateIterator(start: Date, private val end: Date) : Iterator<Date> { private var current = start override fun hasNext() = current <= end override fun next(): Date { val result = current current = current.nextDay() return result } } fun Date.nextDay(): Date { // Simplified next day logic return Date(year, month, day + 1) } fun main() { val start = Date(2024, 1, 1) val end = Date(2024, 1, 3) for (date in start..end) { println(date) } }

8. Invoke Operator

Cho phép gọi object như function:

class Greeter(private val greeting: String) { operator fun invoke(name: String) { println("$greeting, $name!") } } fun main() { val greeter = Greeter("Hello") greeter("Alice") // Hello, Alice! greeter("Bob") // Hello, Bob! }

Ví dụ: Builder pattern

class HtmlBuilder { private val content = StringBuilder() operator fun invoke(block: HtmlBuilder.() -> Unit): String { block() return content.toString() } fun div(text: String) { content.append("<div>$text</div>") } fun p(text: String) { content.append("<p>$text</p>") } } fun main() { val html = HtmlBuilder() val result = html { div("Hello") p("World") } println(result) // <div>Hello</div><p>World</p> }

9. Iterator và Destructuring

Iterator operator

class Countdown(private val start: Int) { operator fun iterator(): Iterator<Int> { return object : Iterator<Int> { private var current = start override fun hasNext() = current >= 0 override fun next() = current-- } } } fun main() { for (i in Countdown(5)) { print("$i ") // 5 4 3 2 1 0 } }

Destructuring (componentN)

class Person(val name: String, val age: Int, val city: String) { operator fun component1() = name operator fun component2() = age operator fun component3() = city } fun main() { val person = Person("Alice", 30, "NYC") val (name, age, city) = person println("$name, $age, $city") // Alice, 30, NYC // Bỏ qua một số components val (n, _, c) = person println("$n from $c") // Alice from NYC }

Note: data class tự động generate componentN() functions.

10. Extension Operator Functions

Có thể định nghĩa operators như extension functions:

// Extension operator cho String operator fun String.times(n: Int): String { return this.repeat(n) } // Extension operator cho List operator fun <T> List<T>.times(n: Int): List<T> { return (1..n).flatMap { this } } fun main() { println("Ha" * 3) // HaHaHa println(listOf(1, 2) * 3) // [1, 2, 1, 2, 1, 2] }

📝 Tóm tắt

CategoryOperatorsFunctions
Arithmetic+, -, *, /, %plus, minus, times, div, rem
Unary+a, -a, !a, ++, --unaryPlus, unaryMinus, not, inc, dec
Comparison==, !=equals
Comparison<, >, <=, >=compareTo
Indexa[i], a[i] = bget, set
Containsin, !incontains
Range.., ..<rangeTo, rangeUntil
Invokea()invoke

Best practices:

  • Chỉ overload operators khi có ý nghĩa logic rõ ràng
  • Operators nên có behavior nhất quán với kỳ vọng của người dùng
  • Sử dụng data class để tự động có equals, hashCode, componentN
Last updated on