Java'da bu anahtar kelime var - final. Sınıflara, yöntemlere, değişkenlere (yöntem parametreleri dahil) uygulanabilir. Bir sınıf için final anahtar sözcüğü, sınıfın alt sınıflara sahip olamayacağı, yani kalıtımın yasak olduğu anlamına gelir... Bu, değişmez (değiştirilemez) nesneler oluştururken kullanışlıdır. Örneğin, String sınıfı final olarak bildirilir.

    public final class String {
    }
    
    class SubString extends String { // Compilation error
    }
Ayrıca, son değiştiricinin soyut sınıflara (absolut anahtar kelimesi olanlar) uygulanamayacağını da not etmeliyim, çünkü bunlar birbirini dışlayan kavramlardır. Nihai bir yöntem için değiştirici, yöntemin alt sınıflarda geçersiz kılınamayacağı anlamına gelir. Bu, orijinal uygulamanın değiştirilmesini önlemek istediğimizde kullanışlıdır.

    public class SuperClass {
        public final void printReport() {
            System.out.println("Report");
        }
    }

    class SubClass extends SuperClass { 
        public void printReport() { //Compilation error
            System.out.println("MyReport");
        }
    }
İlkel türdeki değişkenler için, final anahtar sözcüğü, atanan değerin değiştirilemeyeceği anlamına gelir. Referans değişkenleri için bu, bir nesne atandıktan sonra o nesneye olan referansı değiştiremeyeceğiniz anlamına gelir. Bu önemli! Referans değiştirilemez, ancak nesnenin durumu değiştirilebilir. Java 8 yeni bir kavram getirdi: etkin bir şekilde nihai. Yalnızca değişkenler için geçerlidir (yöntem parametreleri dahil). Sonuç olarak, nihai anahtar kelimenin açıkça yokluğuna rağmen, değişkenin değeri başlatmadan sonra değişmez. Başka bir deyişle, final anahtar sözcüğü böyle bir değişkene derleme hatası olmadan uygulanabilir. Nihai değişkenler yerel sınıflar (yerel iç sınıflar), anonim sınıflar (anonim iç sınıflar) ve akışlar (Stream API) içinde etkili bir şekilde kullanılabilir.

        public void someMethod() {
            // In the example below, both a and b are effectively final, since they are assigned values only once:
            int a = 1;
            int b;
            if (a == 2) b = 3;
            else b = 4;
            // c is NOT effectively final since its value changes
            int c = 10;
            c++;
            
            Stream.of(1, 2).forEach(s-> System.out.println(s + a)); // OK
            Stream.of(1, 2).forEach(s-> System.out.println(s + c)); // Compilation error
        }
Şimdi küçük bir röportaj yapalım. Sonuçta, CodeGym kursunu tamamlamanın amacı bir Java geliştiricisi olmak ve ilginç ve iyi maaşlı bir iş bulmaktır. Öyleyse başlayalım.
  1. Nihai ilan edilen bir dizi hakkında ne söyleyebiliriz?

  2. String sınıfının değişmez olduğunu biliyoruz: sınıf final ilan edildi. Bir dize değeri, final anahtar sözcüğüyle işaretlenmiş bir karakter dizisinde depolanır.


public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

Bir String nesnesinin değerini değiştirebilir miyiz (nesneye yapılan referansı değiştirmeden)? Bunlar gerçek mülakat soruları. Ve uygulama, birçok adayın onlara doğru cevap vermediğini gösteriyor. Özellikle referans değişkenler için final anahtar kelimesinin nasıl kullanıldığını anlamak çok önemlidir. Siz bunu düşünürken CodeGym ekibinden küçük bir ricada bulunacağım. Lütfen metin düzenleyiciye, üzerine tıkladığınızda içeriği gösterilebilen/gizlenebilen bir blok ekleme yeteneği verin. Yanıtlar:
  1. Bir dizi bir nesnedir, bu nedenle final anahtar sözcüğü, diziye bir referans atandıktan sonra referansın değiştirilemeyeceği anlamına gelir. Bununla birlikte, nesnenin durumunu değiştirebilirsiniz.

    
            final int[] array = {1, 2, 3, 4, 5};
            array[0] = 9;	 // OK, because we're changing the contents of the array: {9, 2, 3, 4, 5}
            array = new int[5]; // Compilation error
    
  2. Evet yapabiliriz. Asıl mesele, dikenli final anahtar kelimesinin nesnelerle kullanıldığında ne anlama geldiğini anlamaktır. Reflection API, değerleri değiştirmek için kullanılabilir.


import java.lang.reflect.Field;

class B {
    public static void main(String[] args) throws Exception {
        String value = "Old value";
        System.out.println(value);

        // Get the String class's value field
        Field field = value.getClass().getDeclaredField("value");
        // Make it mutable
        field.setAccessible(true);
        // Set a new value
        field.set(value, "CodeGym".toCharArray());

        System.out.println(value);

        /* Output:
         * Old value
         * CodeGym
         */
    }
}
İlkel bir türün son değişkenini bu şekilde değiştirmeye çalışsaydık hiçbir şey olmayacağını lütfen unutmayın. Kendinizi şuna ikna etmenizi öneririm: örneğin, son bir int alanı olan bir Java sınıfı oluşturun ve Reflection API'sini kullanarak değerini değiştirmeye çalışın. Hepinize iyi şanslar!