Wbrew temu, w co wielu ludzi sądzi, tworzenie niezmiennej klasy niefinal
jest wymagane.
Standardowym argumentem przemawiającym za tworzeniem niezmiennych klas final
jest to, że jeśli tego nie zrobisz, podklasy mogą dodać zmienność, naruszając w ten sposób kontrakt nadklasy. Klienci klasy przyjmą niezmienność, ale będą zaskoczeni, gdy coś spod nich wyskoczy.
Jeśli doprowadzisz ten argument do jego logicznego ekstremum, należy zastosować wszystkie metody final
, ponieważ w przeciwnym razie podklasa mogłaby przesłonić metodę w sposób, który nie jest zgodny z kontraktem jej nadklasy. To interesujące, że większość programistów Javy uważa to za śmieszne, ale w jakiś sposób zgadza się z ideą, że niezmienne klasy powinny być final
. Podejrzewam, że ma to coś wspólnego z tym, że generalnie programiści Java nie są do końca zadowoleni z pojęcia niezmienności i być może z jakimś rozmytym myśleniem związanym z wieloma znaczeniami final
słowa kluczowego w Javie.
Zgodność z umową twojej superklasy nie jest czymś, co może lub powinno być zawsze wymuszane przez kompilator. Kompilator może wymusić pewne aspekty kontraktu (np .: minimalny zestaw metod i ich sygnatury typów), ale istnieje wiele części typowych kontraktów, których kompilator nie może wymusić.
Niezmienność jest częścią kontraktu klasy. To trochę różni się od niektórych rzeczy, do których ludzie są bardziej przyzwyczajeni, ponieważ mówi, czego klasa (i wszystkie podklasy) nie mogą zrobić, podczas gdy myślę, że większość programistów Java (i ogólnie OOP) ma tendencję do myślenia o kontraktach jako odnoszących się do co klasa może zrobić, a nie czego nie może zrobić.
Niezmienność ma również wpływ nie tylko na pojedynczą metodę - ma wpływ na całą instancję - ale nie różni się to zbytnio od sposobu equals
i hashCode
działania języka Java. Te dwie metody mają określoną umowę zawartą w Object
. Ta umowa bardzo dokładnie określa rzeczy, których te metody nie mogą zrobić. Ten kontrakt jest bardziej szczegółowy w podklasach. Bardzo łatwo jest to uchylić equals
lub hashCode
w sposób naruszający umowę. W rzeczywistości, jeśli zastąpisz tylko jedną z tych dwóch metod bez drugiej, istnieje prawdopodobieństwo, że naruszysz umowę. Więc należy equals
i hashCode
zostały uznane final
w Object
tego uniknąć? Myślę, że większość argumentowałaby, że nie powinni. Podobnie nie jest konieczne tworzenie niezmiennych klasfinal
.
To powiedziawszy, większość twoich zajęć, niezmienna lub nie, prawdopodobnie powinna być final
. Zobacz Effective Java Second Edition, pozycja 17: „Projektowanie i dokumentowanie do dziedziczenia albo zabronienie”.
Tak więc poprawna wersja kroku 3 brzmiałaby: „Uczyń klasę ostateczną lub, projektując podklasę, jasno udokumentuj, że wszystkie podklasy muszą być niezmienne”.
java.math.BigInteger
class jest przykładem, jego wartości są niezmienne, ale nie są ostateczne.