JavaRush /Blog Java /Random-ES /Final, constantes e inmutables en Java

Final, constantes e inmutables en Java

Publicado en el grupo Random-ES
¡Hola! La palabra "modificador" ya le resulta familiar. Como mínimo, se ha encontrado con modificadores de acceso (público, privado) y el modificador estático. Hoy hablaremos del modificador final especial . Se puede decir que "cimenta" aquellas áreas de nuestro programa donde necesitamos un comportamiento constante, inequívoco e inmutable. Se puede utilizar en tres áreas de nuestro programa: clases, métodos y variables. Inmutable en Java: final, constantes e Inmutable - 2 Repasémoslos uno por uno. Si una declaración de clase contiene el modificador final , esto significa que no puedes heredar de esta clase. En conferencias anteriores, vimos un ejemplo simple de herencia: teníamos una clase principal Animaly dos clases secundarias, CatyDog
public class Animal {
}

public class Cat extends Animal {
   //..поля и методы класса Cat
}

public class Dog extends Animal {

   //..поля и методы класса Dog
}
Sin embargo, si especificamos Animalun modificador para una clase, las clases tampoco finalpodrán heredar de ella . CatDog
public final class Animal {

}

public class Cat extends Animal {

   //ошибка! Cannot inherit from final Animal
}
El compilador produce inmediatamente un error. Hay muchas clases ya implementadas en Java final. El más famoso de los que usas constantemente es String. Además, si una clase se declara como final, todos sus métodos también se convierten en final. ¿Qué significa? Si se especifica un modificador para un método final, este método no se puede anular. Por ejemplo, tenemos una clase Animalque define un método voice(). Sin embargo, los perros y los gatos claramente “hablan” de manera diferente. Por lo tanto, en cada una de las clases - Caty Dog- crearemos un método voice(), pero lo implementaremos de manera diferente.
public class Animal {

   public void voice() {
       System.out.println("¡Voz!");
   }
}

public class Cat extends Animal {

   @Override
   public void voice() {
       System.out.println("¡Maullar!");
   }
}

public class Dog extends Animal {

   @Override
   public void voice() {
       System.out.println("¡Guau!");
   }
}
En clases Caty Doghemos anulado el método de la clase padre. Ahora el animal vocalizará dependiendo de qué objeto de clase sea:
public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       Dog dog = new Dog();

       cat.voice();
       dog.voice();
   }
}
Conclusión: ¡ Miau! ¡Guau! Sin embargo, si Animaldeclaramos un método en una clase voice()como final, no será posible redefinirlo en otras clases:
public class Animal {

   public final void voice() {
       System.out.println("¡Voz!");
   }
}


public class Cat extends Animal {

   @Override
   public void voice() {//ошибка! final-метод не может быть переопределен!
       System.out.println("¡Maullar!");
   }
}
Entonces nuestros objetos se verán obligados a utilizar el método voice()tal como está definido en la clase principal:
public static void main(String[] args) {

   Cat cat = new Cat();
   Dog dog = new Dog();

   cat.voice();
   dog.voice();
}
Conclusión: ¡Voz! ¡Voz! Ahora sobre finallas variables. De lo contrario se les llama constantes . Primero (y lo más importante), el primer valor asignado a una constante no se puede cambiar. Se asigna una vez y para siempre.
public class Main {

   private static final int CONSTANT_EXAMPLE = 333;

   public static void main(String[] args) {

       CONSTANT_EXAMPLE = 999;//ошибка! Нельзя присвоить новое significado final-переменной!
   }
}
No es necesario inicializar la constante inmediatamente. Esto se puede hacer más tarde. Pero el valor asignado primero permanecerá para siempre.
public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;//так делать можно
}
En segundo lugar, preste atención al nombre de nuestra variable. Las constantes de Java tienen una convención de nomenclatura diferente. Este no es el camelCase al que estamos acostumbrados. En el caso de una variable normal, la llamaríamos ejemplo constante, pero los nombres de las constantes están escritos en mayúsculas y entre las palabras (si hay varias) hay un guión bajo: "CONSTANT_EXAMPLE". ¿Por qué se necesitan constantes? Por ejemplo, serán útiles si utiliza constantemente algún valor constante en un programa. Digamos que decides pasar a la historia y escribir el juego "The Witcher 4" tú solo. Obviamente, el juego utilizará constantemente el nombre del personaje principal: "Geralt de Rivia". Es mejor separar esta línea y los nombres de otros héroes en una constante: el valor que necesitas se almacenará en un solo lugar y definitivamente no cometerás un error al escribirlo por millonésima vez.
public class TheWitcher4 {

   private static final String GERALT_NAME = "Геральт из Ривии";
   private static final String YENNEFER_NAME = "Йеннифэр из Венгерберга";
   private static final String TRISS_NAME = "Трисс Меригольд";

   public static void main(String[] args) {

       System.out.println("Ведьмак 4");
       System.out.println("Это уже четвертая часть Ведьмака, а " + GERALT_NAME + " ниCómo не определится кто ему" +
               " нравится больше: " + YENNEFER_NAME + " o " + TRISS_NAME);

       System.out.println("Но если вы никогда не играли в Ведьмака - начнем сначала.");
       System.out.println("Главного героя зовут " + GERALT_NAME);
       System.out.println(GERALT_NAME + " - ведьмак, охотник на чудовищ");
   }
}
Conclusión:
Ведьмак 4
Это уже четвертая часть Ведьмака, а Геральт из Ривии ниCómo не определится, кто ему нравится больше: Йеннифэр из Венгерберга o Трисс Меригольд.
Но если вы никогда не играли в Ведьмака — начнем сначала.
Главного героя зовут Геральт из Ривии
Геральт из Ривии — ведьмак, охотник на чудовищ
Hemos separado los nombres de los personajes en constantes y ahora definitivamente no los escribiremos mal y no será necesario escribirlos a mano cada vez. Otra ventaja: si eventualmente necesitamos cambiar el valor de una variable a lo largo de todo el programa, basta con hacerlo en un solo lugar, en lugar de rehacerlo manualmente a lo largo de todo el código :)

tipos inmutables

Mientras trabaja en Java, probablemente ya esté acostumbrado al hecho de que el programador controla casi por completo el estado de todos los objetos. Se busca: creó un objeto Cat. Si quería, le cambié el nombre. Si quería, cambiaba su edad, o algo más. Pero en Java existen varios tipos de datos que tienen un estado especial. Son inmutables o Inmutables . Esto significa que si una clase es inmutable, el estado de sus objetos no se puede cambiar. ¿Ejemplos? Puede que te sorprendas, ¡pero el ejemplo más famoso de la clase InmutableString es ! Al parecer, ¿no podemos cambiar el valor de una cadena? Intentemos:
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

   str1 = "I love Python";//но поведение str1 ниCómo не влияет на str2
   System.out.println(str2);//str2 продолжает указывать на строку "I love Java", хотя str1 уже указывает на другой un objeto
}
Conclusión: Amo Java. Amo Java. Después de que escribimos:
str1 = "I love Python";
el objeto con la cadena "Me encanta Java" no ha cambiado y no ha ido a ninguna parte. Existe de forma segura y tiene exactamente el mismo texto dentro que antes. Código:
str1 = "I love Python";
Acabo de crear otro objeto y ahora la variable str1apunta a él. Pero no podemos influir en el objeto "Me encanta Java" de ninguna manera. Bien, ¡intentémoslo de otra manera! ¡La clase Stringestá llena de métodos y algunos de ellos parecen cambiar el estado de la fila! Por ejemplo, existe un método replace(). ¡Cambiemos la palabra "Java" por la palabra "Python" en nuestra línea!
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

   str1.replace("Java", "Python");//попробуем изменить состояние str1, заменив слово "Java" на “Python”
   System.out.println(str2);
}
Conclusión: Amo Java. Amo Java. ¡No volvió a funcionar! ¿Quizás el método de la curva no funciona? Probemos con otro. Por ejemplo, substring(). Recorta una cadena en función de los números de los caracteres transmitidos. Recortemos el nuestro a los primeros 10 caracteres:
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

   str1.substring(10);//обрезаем исходную строку
   System.out.println(str2);
}
Conclusión: Amo Java. Amo Java. Inmutable en Java: final, constantes e Inmutable - 3 Nada ha cambiado. Y no debería haberlo hecho. Como dijimos, los objetos Stringson inmutables. ¿ Cuáles son entonces todos estos métodos de clase String? Pueden recortar la línea, cambiar los caracteres que contiene, etc. ¿Por qué son necesarios entonces si no pasa nada? ¡Ellos pueden! Pero devuelven un nuevo objeto de cadena cada vez. No sirve de nada escribir:
str1.replace("Java", "Python");
- No cambiarás el objeto original. Pero si escribe el resultado del método en una nueva variable de referencia, ¡verá inmediatamente la diferencia!
public static void main(String[] args) {

   String str1 = "I love Java";

   String str2 = str1;//обе переменные-ссылки указывают на одну строку.
   System.out.println(str2);

   String str1AfterReplacement =  str1.replace("Java", "Python");
   System.out.println(str2);

   System.out.println(str1AfterReplacement);
}
Ésta es la única forma en Stringque funcionan todos estos métodos. No puedes hacer nada con el objeto "Me encanta Java" . Simplemente cree un nuevo objeto y escriba: "Nuevo objeto = el resultado de algunas manipulaciones con el objeto "Me encanta Java ". ¿Qué otros tipos son inmutables? Por lo que definitivamente debes recordar ahora: todas las clases contenedoras de los tipos primitivos son inmutables. Integer, Byte, Character, Short, Boolean, Long, Double, Float- todas estas clases crean objetos inmutables . Esto también incluye clases utilizadas para crear números grandes BigIntegery BigDecimal. Recientemente analizamos excepciones y abordamos StackTrace. Entonces: los objetos de la clase java.lang.StackTraceElement también son inmutables. Esto es lógico: si alguien pudiera cambiar los datos de nuestra pila, podría negar todo el trabajo con ellos. Imagine que alguien ingresa a StackTrace y cambia OutOfMemoryError a FileNotFoundException . Y deberías trabajar con esta pila y buscar la causa del error. Y el programa no utiliza archivos en absoluto :) Por lo tanto, para estar seguro, estos objetos se hicieron inmutables. Bueno, con StackTraceElement está más o menos claro. ¿Por qué alguien querría hacer que las cadenas sean inmutables? ¿Cuál sería el problema si fuera posible cambiar sus valores? Probablemente sería aún más conveniente :/ Hay varias razones para esto. En primer lugar, ahorrar memoria. Se pueden colocar cadenas inmutables String Pooly se pueden usar las mismas cada vez en lugar de crear otras nuevas. En segundo lugar, la seguridad. Por ejemplo, la mayoría de los inicios de sesión y contraseñas de cualquier programa son cadenas. La posibilidad de cambiarlos podría generar problemas con la autorización. Hay otras razones, pero aún no las hemos abordado en el aprendizaje de Java; volveremos más adelante.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION