JavaRush /Blogue Java /Random-PT /Final, constantes e imutáveis em Java

Final, constantes e imutáveis em Java

Publicado no grupo Random-PT
Olá! A palavra “modificador” já é familiar para você. No mínimo, você encontrou modificadores de acesso (público, privado) e o modificador estático. Hoje falaremos sobre o modificador final especial . Pode-se dizer que “cimenta” as áreas do nosso programa onde precisamos de um comportamento constante, inequívoco e imutável. Pode ser utilizado em três áreas do nosso programa: classes, métodos e variáveis. Imutável em Java: final, constantes e imutável - 2 Vamos examiná-los um por um. Se uma declaração de classe contém o modificador final , isso significa que você não pode herdar desta classe. Nas aulas anteriores, vimos um exemplo simples de herança: tínhamos uma classe pai Animale duas classes filhas - CateDog
public class Animal {
}

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

public class Dog extends Animal {

   //..поля и методы класса Dog
}
No entanto, se especificarmos Animalum modificador para uma classe, as classes também finalnão poderão herdar dele . CatDog
public final class Animal {

}

public class Cat extends Animal {

   //ошибка! Cannot inherit from final Animal
}
O compilador produz imediatamente um erro. Existem muitas classes já implementadas em Java final. O mais famoso daqueles que você usa constantemente é o String. Além disso, se uma classe for declarada como final, todos os seus métodos também se tornarão final. O que isso significa? Se um modificador for especificado para um método final, esse método não poderá ser substituído. Por exemplo, temos uma classe Animalque define um método voice(). No entanto, cães e gatos claramente “falam” de forma diferente. Portanto, em cada uma das classes - Cate Dog- criaremos um método voice(), mas iremos implementá-lo de forma diferente.
public class Animal {

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

public class Cat extends Animal {

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

public class Dog extends Animal {

   @Override
   public void voice() {
       System.out.println("Woof!");
   }
}
Nas classes Cate Dogsubstituímos o método da classe pai. Agora o animal irá vocalizar dependendo da classe do objeto:
public class Main {

   public static void main(String[] args) {

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

       cat.voice();
       dog.voice();
   }
}
Conclusão: Miau! Uau! Porém, se Animaldeclararmos um método em uma classe voice()como final, não será possível redefini-lo em outras classes:
public class Animal {

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


public class Cat extends Animal {

   @Override
   public void voice() {//ошибка! final-метод не может быть переопределен!
       System.out.println("Meow!");
   }
}
Então nossos objetos serão forçados a usar o método voice()conforme definido na classe pai:
public static void main(String[] args) {

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

   cat.voice();
   dog.voice();
}
Conclusão: Voz! Voz! Agora sobre finalas variáveis. Caso contrário, eles são chamados de constantes . Primeiro (e mais importante), o primeiro valor atribuído a uma constante não pode ser alterado. É atribuído de uma vez por todas.
public class Main {

   private static final int CONSTANT_EXAMPLE = 333;

   public static void main(String[] args) {

       CONSTANT_EXAMPLE = 999;//ошибка! Нельзя присвоить новое meaning final-переменной!
   }
}
A constante não precisa ser inicializada imediatamente. Isso pode ser feito mais tarde. Mas o valor atribuído primeiro permanecerá para sempre.
public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;//так делать можно
}
Em segundo lugar, preste atenção ao nome da nossa variável. As constantes Java têm uma convenção de nomenclatura diferente. Este não é o camelCase com o qual estamos acostumados. No caso de uma variável regular, chamaríamos de constanteExample, mas os nomes das constantes são escritos em maiúsculas, e entre as palavras (se houver várias) há um sublinhado - “CONSTANT_EXAMPLE”. Por que as constantes são necessárias? Por exemplo, eles serão úteis se você usar constantemente algum valor constante em um programa. Digamos que você decidiu entrar na história e escrever o jogo “The Witcher 4” sozinho. O jogo obviamente usará constantemente o nome do personagem principal – “Geralt of Rivia”. É melhor separar esta linha e os nomes de outros heróis em uma constante: o valor que você precisa será armazenado em um só lugar e você definitivamente não cometerá erros ao digitá-lo pela milioné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 + " ниHow не определится кто ему" +
               " нравится больше: " + YENNEFER_NAME + " or " + TRISS_NAME);

       System.out.println("Но если вы никогда не играли в Ведьмака - начнем сначала.");
       System.out.println("Главного героя зовут " + GERALT_NAME);
       System.out.println(GERALT_NAME + " - ведьмак, охотник на чудовищ");
   }
}
Conclusão:
Ведьмак 4
Это уже четвертая часть Ведьмака, а Геральт из Ривии ниHow не определится, кто ему нравится больше: Йеннифэр из Венгерберга or Трисс Меригольд.
Но если вы никогда не играли в Ведьмака — начнем сначала.
Главного героя зовут Геральт из Ривии
Геральт из Ривии — ведьмак, охотник на чудовищ
Separamos os nomes dos personagens em constantes e agora definitivamente não iremos escrevê-los incorretamente e não haverá necessidade de escrevê-los à mão todas as vezes. Outra vantagem: se eventualmente precisarmos alterar o valor de uma variável ao longo do programa, basta fazê-lo em um só lugar, em vez de refazê-lo manualmente em todo o código :)

Tipos imutáveis

Durante seu tempo trabalhando em Java, você provavelmente já está acostumado com o fato de que o programador controla quase completamente o estado de todos os objetos. Procurado - criou um objeto Cat. Se eu quisesse, eu renomeava. Se ele quisesse, ele mudava de idade ou outra coisa. Mas em Java existem vários tipos de dados que possuem um estado especial. Eles são imutáveis , ou Imutáveis . Isso significa que se uma classe for imutável, o estado de seus objetos não poderá ser alterado. Exemplos? Você pode se surpreender, mas o exemplo mais famoso da classe Imutável é String! Parece que não podemos alterar o valor de uma string? Vamos tentar:
public static void main(String[] args) {

   String str1 = "I love Java";

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

   str1 = "I love Python";//но поведение str1 ниHow не влияет на str2
   System.out.println(str2);//str2 продолжает указывать на строку "I love Java", хотя str1 уже указывает на другой an object
}
Conclusão: eu amo Java, eu amo Java Depois que escrevemos:
str1 = "I love Python";
o objeto com a string "I love Java" não mudou e não foi a lugar nenhum. Ele existe com segurança e contém exatamente o mesmo texto de antes. Código:
str1 = "I love Python";
acabei de criar outro objeto e agora a variável str1aponta para ele. Mas não podemos influenciar o objeto “Eu amo Java” de forma alguma. Ok, vamos tentar de forma diferente! A classe Stringestá cheia de métodos e alguns deles parecem mudar o estado da linha! Por exemplo, existe um método replace(). Vamos mudar a palavra “Java” pela palavra “Python” em nossa linha!
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);
}
Conclusão: eu amo Java, eu amo Java. Não deu certo de novo! Talvez o método da curva não funcione? Vamos tentar outro. Por exemplo, substring(). Corta uma string com base nos números dos caracteres transmitidos. Vamos reduzir o nosso para os primeiros 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);
}
Conclusão: eu amo Java. Eu amo Java. Imutável em Java: final, constantes e imutável - 3 Nada mudou. E não deveria. Como dissemos, os objetos Stringsão imutáveis. O que são então todos esses métodos de classe String? Eles podem cortar a linha, alterar os caracteres nela, etc. Por que eles são necessários se nada acontecer? Eles podem! Mas eles retornam um novo objeto string a cada vez. Não adianta escrever:
str1.replace("Java", "Python");
- você não alterará o objeto original. Mas se você escrever o resultado do método em uma nova variável de referência, verá imediatamente a diferença!
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);
}
Esta é a única maneira de todos esses métodos Stringfuncionarem. Você não pode fazer nada com o objeto "I love Java" . Basta criar um novo objeto e escrever: “Novo objeto = resultado de algumas manipulações com o objeto “Eu amo Java” .” Que outros tipos são imutáveis? Pelo que você definitivamente precisa lembrar agora: todas as classes wrapper sobre tipos primitivos são imutáveis. Integer, Byte, Character, Short, Boolean, Long, Double, Float- todas essas classes criam objetos imutáveis . Isso também inclui classes usadas para criar números grandes - BigIntegere BigDecimal. Recentemente, passamos por exceções e abordamos o StackTrace. Portanto: os objetos da classe java.lang.StackTraceElement também são imutáveis. Isso é lógico: se alguém pudesse alterar os dados em nossa pilha, isso poderia anular todo o trabalho com ela. Imagine que alguém entre no StackTrace e altere OutOfMemoryError para FileNotFoundException . E você deve trabalhar com essa pilha e procurar a causa do erro. E o programa não usa arquivos :) Portanto, por segurança, esses objetos foram tornados imutáveis. Bem, com StackTraceElement fica mais ou menos claro. Por que alguém iria querer tornar as strings imutáveis? Qual seria o problema se fosse possível alterar seus valores. Provavelmente seria ainda mais conveniente :/ Existem várias razões para isso. Em primeiro lugar, economizando memória. Strings imutáveis ​​podem ser colocadas String Poole as mesmas podem ser usadas todas as vezes, em vez de criar novas. Em segundo lugar, segurança. Por exemplo, a maioria dos logins e senhas em qualquer programa são strings. A possibilidade de alterá-los pode gerar problemas de autorização. Existem outros motivos, mas ainda não chegamos a eles no aprendizado de Java – voltaremos mais tarde.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION