CodeGym /Java блог /Случаен /Да поговорим за крайната ключова дума в Java
John Squirrels
Ниво
San Francisco

Да поговорим за крайната ключова дума в Java

Публикувано в групата
Java има тази ключова дума — final. Може да се прилага към класове, методи, променливи (включително параметри на метода). За даден клас ключовата дума final означава, че класът не може да има подкласове, т.е. наследяването е забранено... Това е полезно при създаване на неизменни (непроменяеми) обекти. Например класът String е деклариран като final.

    public final class String {
    }
    
    class SubString extends String { // Compilation error
    }
Трябва също така да отбележа, че финалният модификатор не може да се прилага към абстрактни класове (тези с ключова дума abstract), защото това са взаимно изключващи се концепции. За окончателен метод модификаторът означава, че методът не може да бъде заменен в подкласове. Това е полезно, когато искаме да предотвратим промяната на оригиналната реализация.

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

    class SubClass extends SuperClass { 
        public void printReport() { //Compilation error
            System.out.println("MyReport");
        }
    }
За променливи от примитивен тип ключовата дума final означава, че стойността, веднъж присвоена, не може да бъде променена. За референтни променливи това означава, че след присвояване на обект не можете да промените препратката към този обект. Това е важно! Препратката не може да бъде променена, но състоянието на обекта може да бъде променено. Java 8 въведе нова концепция: ефективно финал. Прилага се само за променливи (включително параметри на метода). Изводът е, че въпреки явната липса на ключовата дума final, стойността на променливата не се променя след инициализацията. С други думи, ключовата дума final може да се приложи към такава променлива без грешка при компorране. Ефективно крайните променливи могат да се използват в локални класове (локални вътрешни класове), анонимни класове (анонимни вътрешни класове) и потоци (Stream API).

        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
        }
Сега, нека направим малко интервю. В крайна сметка целта на завършването на курса по CodeGym е да станете Java разработчик и да си намерите интересна и добре платена работа. И така, да започваме.
  1. Какво можем да кажем за масив, който е обявен за окончателен?

  2. Знаем, че класът String е неизменен: класът е обявен за окончателен. Стойност на низ се съхранява в масив от символи, който е маркиран с ключовата дума final.


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

Можем ли да заменим стойността на String обект (без да променяме препратката към обекта)? Това са истински въпроси за интервю. А практиката показва, че много кандидати не отговарят правилно на тях. Разбирането How се използва крайната ключова дума, особено за референтни променливи, е много важно. Докато обмисляте това, ще отправя малка молба към екипа на CodeGym. Моля, дайте възможност на текстовия редактор да добави блок, чието съдържание може да бъде показано/скрито, когато щракнете върху него. Отговори:
  1. Масивът е обект, така че ключовата дума final означава, че след като се присвои препратка към масива, препратката не може да бъде променена. Въпреки това можете да промените състоянието на обекта.

    
            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. Да, можем. Основното нещо е да разберете Howво означава ключовата дума thorny final, когато се използва с обекти. API Reflection може да се използва за замяна на стойности.


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
         */
    }
}
Моля, имайте предвид, че ако се бяхме опитали да променим крайната променлива от примитивен тип по този начин, нищо нямаше да се случи. Предлагам ви да се убедите сами: създайте Java клас, например, с крайно int поле и опитайте да промените стойността му с помощта на Reflection API. Успех на всички!
Коментари
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION