Wbrew temu, w co wielu ludzi sądzi, tworzenie niezmiennej klasy niefinal jest wymagane.
Standardowym argumentem przemawiającym za tworzeniem niezmiennych klas finaljest 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 finalsł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 equalsi hashCodedział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ć equalslub hashCodew 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 equalsi hashCodezostały uznane finalw Objecttego 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.BigIntegerclass jest przykładem, jego wartości są niezmienne, ale nie są ostateczne.