JavaRush /Java Blog /Random-KO /Java의 최종, 상수 및 불변

Java의 최종, 상수 및 불변

Random-KO 그룹에 게시되었습니다
안녕하세요! "수정자"라는 단어는 이미 여러분에게 익숙합니다. 최소한 액세스 수정자(공개, 비공개)와 정적 수정자를 접했습니다. 오늘은 특별한 최종 수식어 에 대해 이야기하겠습니다 . 이는 우리 프로그램에서 지속적이고, 모호하지 않으며, 변하지 않는 행동이 필요한 영역을 "강화"한다고 말할 수 있습니다. 이는 프로그램의 세 가지 영역인 클래스, 메소드 및 변수에서 사용될 수 있습니다. Java의 불변: 최종, 상수 및 불변 - 2 하나씩 살펴보겠습니다. 클래스 선언에 final 수정자가 포함되어 있으면 이 클래스에서 상속할 수 없다는 의미입니다. 이전 강의에서 우리는 상속의 간단한 예를 보았습니다. 부모 클래스 Animal와 두 개의 자식 클래스가 있었습니다 Cat.Dog
public class Animal {
}

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

public class Dog extends Animal {

   //..поля и методы класса Dog
}
Animal그러나 클래스에 수정자를 지정하면 클래스 도 해당 클래스에서 final상속을 받을 수 없습니다 . CatDog
public final class Animal {

}

public class Cat extends Animal {

   //ошибка! Cannot inherit from final Animal
}
컴파일러는 즉시 오류를 생성합니다. Java에는 이미 많은 클래스가 구현되어 있습니다 final. 지속적으로 사용하는 것 중 가장 유명한 것은 입니다 String. 또한 클래스가 로 선언되면 final해당 클래스의 모든 메서드도 가 됩니다 final. 무슨 뜻이에요? 메소드에 수정자가 지정된 경우 final이 메소드를 재정의할 수 없습니다. Animal예를 들어 메소드를 정의하는 클래스가 있습니다 voice(). 그러나 개와 고양이는 분명히 다르게 "말"합니다. 따라서 각 클래스에서 메소드를 생성 Cat하지만 이를 다르게 구현할 것입니다. Dogvoice()
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!");
   }
}
클래스에서는 Cat부모 Dog클래스의 메서드를 재정의했습니다. 이제 동물은 클래스 개체가 무엇인지에 따라 소리를 냅니다.
public class Main {

   public static void main(String[] args) {

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

       cat.voice();
       dog.voice();
   }
}
결론: 야옹! 씨! 그러나 클래스의 Animal메소드를 voice()로 선언하면 final다른 클래스에서 이를 재정의하는 것이 불가능합니다.
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!");
   }
}
voice()그런 다음 객체는 부모 클래스에 정의된 대로 메서드를 사용하도록 강제됩니다 .
public static void main(String[] args) {

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

   cat.voice();
   dog.voice();
}
결론: 목소리! 목소리! 이제 final-변수에 대해 알아보겠습니다. 그렇지 않으면 상수 라고 합니다 . 첫째(가장 중요한 점)는 상수에 할당된 첫 번째 값을 변경할 수 없다는 것입니다. 그것은 단번에 영원히 할당됩니다.
public class Main {

   private static final int CONSTANT_EXAMPLE = 333;

   public static void main(String[] args) {

       CONSTANT_EXAMPLE = 999;//ошибка! Нельзя присвоить новое meaning final-переменной!
   }
}
상수를 즉시 초기화할 필요는 없습니다. 이 작업은 나중에 수행할 수 있습니다. 그러나 처음에 할당된 값은 영원히 유지됩니다.
public static void main(String[] args) {

   final int CONSTANT_EXAMPLE;

   CONSTANT_EXAMPLE = 999;//так делать можно
}
둘째, 변수 이름에 주의하세요. Java 상수에는 다른 명명 규칙이 있습니다. 이것은 우리가 익숙한 CamelCase가 아닙니다. 일반 변수의 경우 ConstantExample이라고 부르지만 상수 이름은 대문자로 작성되고 단어 사이에는 (여러 개가 있는 경우) 밑줄인 "CONSTANT_EXAMPLE"이 있습니다. 상수는 왜 필요한가요? 예를 들어, 프로그램에서 일정한 값을 지속적으로 사용하는 경우 유용합니다. 당신이 역사에 이름을 남기고 "The Witcher 4" 게임을 혼자서 작성하기로 결정했다고 가정해 보겠습니다. 이 게임은 분명히 주인공의 이름인 "Geralt of Rivia"를 계속 사용할 것입니다. 이 줄과 다른 영웅의 이름을 상수로 분리하는 것이 더 좋습니다. 필요한 값은 한 곳에 저장되며, 백만 번 입력해도 실수하지 않을 것입니다.
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 + " - ведьмак, охотник на чудовищ");
   }
}
결론:
Ведьмак 4
Это уже четвертая часть Ведьмака, а Геральт из Ривии ниHow не определится, кто ему нравится больше: Йеннифэр из Венгерберга or Трисс Меригольд.
Но если вы никогда не играли в Ведьмака — начнем сначала.
Главного героя зовут Геральт из Ривии
Геральт из Ривии — ведьмак, охотник на чудовищ
문자의 이름을 상수로 분리해 두었으니 이제 철자를 틀리는 일도 절대 없을 것이고, 매번 손으로 쓸 필요도 없을 것입니다. 또 다른 장점: 결국 전체 프로그램에서 변수 값을 변경해야 하는 경우 전체 코드에서 수동으로 다시 실행하는 대신 한 곳에서 수행하면 충분합니다. :)

불변 유형

Java로 작업하는 동안 프로그래머가 모든 개체의 상태를 거의 완벽하게 제어한다는 사실에 이미 익숙해졌을 것입니다. 구함 - 개체를 만들었습니다 Cat. 원하면 이름을 바꿨습니다. 그가 원한다면 나이 등을 변경했습니다. 그러나 Java에는 특별한 상태를 갖는 여러 데이터 유형이 있습니다. immutable 또는 Immutable 입니다 . 즉, 클래스가 변경 불가능하면 해당 객체의 상태도 변경할 수 없습니다. 예? 놀라실 수도 있지만 Immutable 클래스의 가장 유명한 예는 String! 문자열의 값을 변경할 수 없는 것 같나요? 해보자:
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
}
결론: 저는 Java를 좋아합니다. 저는 Java를 좋아합니다. 작성한 후:
str1 = "I love Python";
"I love Java" 라는 문자열이 있는 개체는 변경되지 않았으며 아무데도 가지 않았습니다. 그것은 안전하게 존재하며 그 안에는 이전과 똑같은 텍스트가 들어 있습니다. 암호:
str1 = "I love Python";
방금 다른 개체를 만들었고 이제 변수가 str1해당 개체를 가리킵니다. 그러나 우리는 "I love Java" 객체 에 어떤 식으로든 영향을 미칠 수 없습니다. 좋아, 다르게 시도해 보자! 클래스 String는 메소드로 가득 차 있으며 그 중 일부는 행의 상태를 변경하는 것 같습니다! 예를 들어 메소드가 있습니다 replace(). 우리 줄에서 "Java"라는 단어를 "Python"이라는 단어로 바꾸자!
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);
}
결론: 나는 Java를 좋아한다. 나는 Java를 좋아한다. 그것은 또 실패했다! 어쩌면 곡선 방법이 작동하지 않는 것일까요? 다른 것을 시도해 보겠습니다. 예를 들어, substring(). 전송된 문자 수를 기준으로 문자열을 자릅니다. 처음 10자로 자릅니다.
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);
}
결론: 저는 Java를 좋아합니다. 저는 Java를 좋아합니다. Java의 불변: 최종, 상수 및 불변 - 3 아무것도 변하지 않았습니다. 그리고 그러지 말았어야 했어요. 앞서 말했듯이 객체는 String불변입니다. 그러면 이 모든 클래스 메소드는 무엇입니까 String? 줄을 다듬고, 줄 안의 문자를 바꾸는 등의 작업을 할 수 있습니다. 아무 일도 일어나지 않으면 왜 필요합니까? 그들은 할 수있다! 그러나 매번 새로운 문자열 객체를 반환합니다. 다음과 같이 써도 소용이 없습니다.
str1.replace("Java", "Python");
- 원본 개체는 변경되지 않습니다. 그러나 메소드의 결과를 새 참조 변수에 쓰면 즉시 차이점을 확인할 수 있습니다!
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);
}
이것이 모든 방법이 작동하는 유일한 방법입니다 String. "I love Java" 개체 로는 아무 것도 할 수 없습니다 . 새 개체를 만들고 다음과 같이 작성하세요. "새 개체 = "I love Java" 개체 를 조작한 결과 ." 변경 불가능한 다른 유형은 무엇입니까? 지금 확실히 기억해야 할 점은 기본 유형에 대한 모든 래퍼 클래스는 변경할 수 없다는 것입니다. Integer, Byte, Character, Short, Boolean, Long, Double, Float- 이 모든 클래스는 불변 객체를 생성합니다. BigInteger여기에는 큰 숫자를 생성하는 데 사용되는 클래스도 포함됩니다 BigDecimal. 우리는 최근 예외를 겪고 StackTrace. 따라서 java.lang.StackTraceElement 클래스의 객체 도 변경할 수 없습니다. 이는 논리적입니다. 누군가가 스택의 데이터를 변경할 수 있다면 그에 대한 모든 작업이 무효화될 수 있습니다. 누군가가 StackTrace 에 들어가서 OutOfMemoryError를 FileNotFoundException 으로 변경한다고 상상해 보세요 . 그리고 이 스택을 사용하여 오류의 원인을 찾아야 합니다. 그리고 프로그램은 파일을 전혀 사용하지 않습니다 :) 따라서 안전을 위해 이러한 객체는 변경할 수 없도록 만들어졌습니다. 글쎄, StackTraceElement를 사용하면 어느 정도 명확해집니다. 왜 문자열을 불변으로 만들고 싶어할까요? 그들의 가치관을 바꿀 수 있다면 무엇이 문제가 될까요? 아마도 훨씬 더 편리할 것입니다./ 여기에는 몇 가지 이유가 있습니다. 첫째, 메모리를 절약합니다. 불변 문자열을 배치할 수 String Pool있으며 새 문자열을 만드는 대신 매번 동일한 문자열을 사용할 수 있습니다. 둘째, 안전. 예를 들어, 모든 프로그램에서 대부분의 로그인과 비밀번호는 문자열입니다. 이를 변경하면 인증에 문제가 발생할 수 있습니다. 다른 이유도 있지만 아직 Java를 배우지 못한 이유는 나중에 다시 다루겠습니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION