equals، hashCode، toString
جزء من قسم البرمجة كائنية التوجه في رحلة Kotlin على Coddy. الدرس 35 من 57.
ترث كل فئة toString() وequals() وhashCode() من Any. تعمل الإصدارات الموروثة على الهوية: تعطي toString() اسم الفئة ورمز تجزئة، وتكون equals() مساوية لـ true للكائن نفسه فقط. يؤدي تجاوز toString() إلى منح الكائنات نصًا مقروءًا، ويُستخدم ذلك بواسطة println وقوالب السلاسل النصية:
class Money(val cents: Int) {
override fun toString() = "$%d.%02d".format(cents / 100, cents % 100)
}داخل main:
val price = Money(1250)
println(price)
println("total: ${Money(99)}")الناتج:
$12.50
total: $0.99== يستدعي equals()، بينما يتحقق === مما إذا كان مرجعان يشيران إلى الكائن نفسه. للمقارنة حسب القيمة، أعد تعريف equals. وسيطها هو Any?، لذا تتحقق أولًا من النوع ثم تقارن الخصائص ذات الصلة:
class Isbn(code: String) {
val digits = code.filter { it.isDigit() }
override fun equals(other: Any?) = other is Isbn && other.digits == digits
override fun hashCode() = digits.hashCode()
}داخل main:
val a = Isbn("978-0-441-17271-9")
val b = Isbn("9780441172719")
println(a == b)
println(a === b)الناتج:
true
falseيجب أن تكون للكائنات المتساوية رموز تجزئة متساوية. تبحث HashSet وHashMap عن الإدخالات باستخدام hashCode() أولًا، ولا تستدعي equals() إلا بعد ذلك، لذا فإن تجاوز equals دون hashCode يجعل الكائنات المتساوية تبدو مختلفة فيهما. تجاوز كليهما دائمًا، واحسبهما من الخصائص نفسها:
class Isbn(code: String) {
val digits = code.filter { it.isDigit() }
override fun equals(other: Any?) = other is Isbn && other.digits == digits
override fun hashCode() = digits.hashCode()
override fun toString() = "ISBN $digits"
}داخل main:
val shelf = hashSetOf(Isbn("978-0-441-17271-9"), Isbn("9780441172719"), Isbn("0-14-143951-3"))
println(shelf.size)
println(Isbn("9780441172719") in shelf)الناتج:
2
trueيُنشئ صنف البيانات الثلاثة جميعها من خصائص مُنشئه. اكتبها بنفسك عندما ينبغي أن تستخدم المساواة عددًا أقل من الخصائص أو صيغةً موحّدة، مثل عنوان بريد إلكتروني يتجاهل حالة الأحرف:
class User(val email: String, val name: String) {
private val key = email.trim().lowercase()
override fun equals(other: Any?) = other is User && other.key == key
override fun hashCode() = key.hashCode()
override fun toString() = "$name <$key>"
}داخل main:
val users = listOf(User("Ada@Example.com", "Ada"), User("ada@example.com ", "A. Lovelace"))
println(users.distinct())الناتج:
[Ada <ada@example.com>]التحدي
سهليكون المنتجان متماثلين عندما تتطابق قيمة sku الخاصة بهما، بغضّ النظر عمّا تقوله الحقول الأخرى. تجاوز equals() وhashCode() في Product بالاعتماد على sku فقط، وطبّق toString() بحيث تتم طباعة المنتج بالشكل A1 tea 450. ثم أكمل mergeCatalog(products)، بحيث يحتفظ بأول ظهور لكل منتج بالترتيب الأصلي.
يقرأ الكود الموفَّر المنتجات على هيئة أسطر بتنسيق sku,name,price، وسطر أخير يحتوي على sku للبحث عنه. ويطبع كل منتج تم الاحتفاظ به، وremoved: 2 وA1 in catalog: true، مع البحث عن sku في HashSet.
يجب أن تضع كودك في Product.kt وFunctions.kt. يحتوي Main.kt على كود الإدخال/الإخراج الموفَّر، ولا يمكن تعديله.
جرّب بنفسك
fun main() {
// كود الإدخال/الإخراج المُزوَّد: أبقِه كما هو
val input = generateSequence(::readLine).toList()
val products = input.dropLast(1).map { line ->
val (sku, name, price) = line.split(",")
Product(sku, name, price.toInt())
}
val kept = mergeCatalog(products)
for (p in kept) println(p)
println("removed: ${products.size - kept.size}")
val probe = Product(input.last(), "?", 0)
println("${input.last()} in catalog: ${probe in kept.toHashSet()}")
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1الفئات والكائنات
العمل مع الملفاتتعريف الفئاتالمنشئات الأساسيةكتل init والتحقق من الصحةالمنشئات الثانويةمراجعة - بطاقة المكتبة4الوراثة
الأصناف المفتوحة والأصناف الفرعيةتجاوز الأعضاءsuper والمنشئاتالأصناف المجرّدةمراجعة - دليل الموظفين7الفئات الخاصة
فئات البياناتفئات التعدادالتسلسلات الهرمية المغلقةequals، hashCode، toStringمراجعة - متتبّع الطلباتتدرّب بنفسك: Playground لـ Kotlin