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. 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
Animal
e duas classes filhas - Cat
eDog
public class Animal {
}
public class Cat extends Animal {
//..поля и методы класса Cat
}
public class Dog extends Animal {
//..поля и методы класса Dog
}
No entanto, se especificarmos Animal
um modificador para uma classe, as classes também final
não poderão herdar dele . Cat
Dog
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 Animal
que define um método voice()
. No entanto, cães e gatos claramente “falam” de forma diferente. Portanto, em cada uma das classes - Cat
e 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 Cat
e Dog
substituí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 Animal
declararmos 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 final
as 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 objetoCat
. 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 str1
aponta para ele. Mas não podemos influenciar o objeto “Eu amo Java” de forma alguma. Ok, vamos tentar de forma diferente! A classe String
está 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. Nada mudou. E não deveria. Como dissemos, os objetos String
sã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 String
funcionarem. 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 - BigInteger
e 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 Pool
e 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.
GO TO FULL VERSION