JavaRush /Java Blog /Random-TW /Java 中的 Final、常數與不可變

Java 中的 Final、常數與不可變

在 Random-TW 群組發布
你好!「修飾符」這個詞你已經很熟悉了。至少,您遇到過存取修飾符(public、private)和 static 修飾符。今天我們來談談特殊的final修飾符。可以說,它「鞏固」了我們計劃中需要持續、明確、不變行為的領域。它可以用在我們程式的三個區域:類別、方法和變數。 Java 中的不可變:final、常數和 Immutable - 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因此,在每個類別中Dog,我們將創建一個方法voice(),但我們將以不同的方式實現它。
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!");
   }
}
在類別中CatDog我們重寫了父類別的方法。現在動物會根據它是什麼類物件發出聲音:
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 常數有不同的命名約定。這不是我們習慣的駝峰命名法。對於常規變量,我們將其稱為constantExample,但常數的名稱是大寫的,並且在單字之間(如果有多個單字)有一個底線 - “CONSTANT_EXAMPLE”。為什麼需要常數?例如,如果您在程式中不斷使用某些常數值,它們就會派上用場。假設您決定獨自編寫《巫師 4》遊戲並載入史冊。遊戲顯然會不斷使用主角的名字——「利維亞的傑洛特」。最好將這一行和其他英雄的名字分開成一個常數:您需要的值將儲存在一個地方,並且您在第一百萬次輸入時絕對不會出錯。
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類別最著名的例子是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指向它。但我們無法以任何方式影響「我愛 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 中的不可變:final、常數和 Immutable - 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。您無法對“我愛 Java”物件執行任何操作。只需建立一個新物件並寫入:“新物件 = 使用“我愛 Java”物件進行一些操作的結果。” 還有哪些其他類型是不可變的? 現在你肯定需要記住的是——所有基本類型上的包裝類別都是不可變的。 Integer, Byte, Character, Short, Boolean, Long, Double, Float- 所有這些類別都建立不可變物件。這也包括用於創建大數的類別 -BigIntegerBigDecimal。我們最近經歷了例外情況並談到了StackTrace。因此:java.lang.StackTraceElement類別的物件也是不可變的。這是合乎邏輯的:如果有人可以更改堆疊上的數據,則可能會導致所有相關工作失效。想像有人進入StackTrace並將OutOfMemoryError改為FileNotFoundException。您應該使用該堆疊並查找錯誤原因。並且該程式根本不使用文件:)因此,為了安全起見,這些物件被設定為不可變的。嗯,有了StackTraceElement,情況或多或少就很清楚了。為什麼有人想要使字串不可變?如果可以改變他們的價值觀,會出現什麼問題。這可能會更方便:/ 這樣做有幾個原因。首先,節省內存。可以放置不可變的字串String Pool,並且每次都可以使用相同的字串,而不是建立新的字串。其次,安全。例如,任何程式中的大多數登入名稱和密碼都是字串。更改它們的可能性可能會導致授權問題。還有其他原因,但我們在學習 Java 時還沒有觸及它們——我們稍後會回來。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION