programowanieProgramista Backendowy

Wyjaśnij działanie operatorów '==' i '===' w Kotlinie. Jaka jest specyfika porównania obiektów i typów wartości, co dzieje się w tle podczas porównania i jak uniknąć powszechnego błędu związanego z równością?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

W Kotlinie istnieją dwa operatory do porównywania:

  • ==porównanie strukturalne (odpowiada .equals()). Sprawdza zawartość: a == b wywołuje a?.equals(b) ?: (b == null).
  • ===porównanie referencyjne. Sprawdza, czy obie zmienne wskazują na ten sam obiekt: a === b jest równoważne Java a == b dla obiektów.

Dla typów prymitywnych (np. Int): == i === mogą się zachowywać identycznie z powodu autoboxingu, ale w ogólnym przypadku należy używać ==.

Przykład kodu

val a = "Kotlin" val b = "Kotlin" val c = a println(a == b) // true (porównanie zawartości) println(a === b) // false (różne referencje — łańcuchy są internowane, w zależności od kompilatora) println(a === c) // true (to sam obiekt)

Pytanie z podstępem.

Jaka jest różnica między a.equals(b) a a == b w Kotlinie?

Niektórzy twierdzą, że nie ma różnicy, jednak jeśli a jest nullable, to wywołanie a.equals(b) spowoduje NullPointerException, podczas gdy a == b jest bezpieczne i zwróci true, jeśli oba są null, lub false, jeśli tylko jeden z nich jest null.

Przykład:

val a: String? = null val b: String? = null println(a == b) // true println(a?.equals(b)) // null (a nie true, ale nie ma awarii) println(a.equals(b)) // NullPointerException

Przykłady rzeczywistych błędów spowodowanych brakiem znajomości niuansów tematu.


Historia

W dużym projekcie aktywnie porównywano nullable łańcuchy za pomocą a.equals(b), nie zdając sobie sprawy, że przy a == null aplikacja się zawiesza. Błąd powtarzał się dosyć rzadko, ale prowadził do fatalnych awarii w produkcji — naprawiono go zastępując a == b.


Historia

Podczas porównywania obiektów przez === oczekiwano porównania zawartości, ale === sprawdza identyczność obiektów — okazało się, że dwa różne łańcuchy z identyczną zawartością nie są sobie równe przez ===, co złamało logikę cachowania danych.


Historia

Pracując z wartościami Int-typami w opakowaniach (np. z kolekcji), deweloperzy porównywali je przez === i otrzymywali nieoczekiwane wyniki, ponieważ instancje obiektów różnych liczb niekoniecznie były internowane jak prymitywy. Prowadziło to do nieprawidłowego zachowania podczas pracy z kolekcjami obiektów.