你好!「修飾符」這個詞你已經很熟悉了。至少,您遇到過存取修飾符(public、private)和 static 修飾符。今天我們來談談特殊的final修飾符。可以說,它「鞏固」了我們計劃中需要持續、明確、不變行為的領域。它可以用在我們程式的三個區域:類別、方法和變數。 讓我們一一分析一下。如果類別聲明包含final修飾符,則表示您不能從該類別繼承。在之前的講座中,我們看到了一個簡單的繼承範例:我們有一個父類別
Animal
和兩個子類別 -Cat
並且Dog
public class Animal {
}
public class Cat extends Animal {
//..поля и методы класса Cat
}
public class Dog extends Animal {
//..поля и методы класса Dog
}
但是,如果我們為類別指定Animal
修飾符,類別也final
將無法從它繼承。 Cat
Dog
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!");
}
}
在類別中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 常數有不同的命名約定。這不是我們習慣的駝峰命名法。對於常規變量,我們將其稱為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 一切都沒有改變。它不應該有。正如我們所說,物件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
- 所有這些類別都建立不可變物件。這也包括用於創建大數的類別 -BigInteger
和BigDecimal
。我們最近經歷了例外情況並談到了StackTrace
。因此:java.lang.StackTraceElement類別的物件也是不可變的。這是合乎邏輯的:如果有人可以更改堆疊上的數據,則可能會導致所有相關工作失效。想像有人進入StackTrace並將OutOfMemoryError改為FileNotFoundException。您應該使用該堆疊並查找錯誤原因。並且該程式根本不使用文件:)因此,為了安全起見,這些物件被設定為不可變的。嗯,有了StackTraceElement,情況或多或少就很清楚了。為什麼有人想要使字串不可變?如果可以改變他們的價值觀,會出現什麼問題。這可能會更方便:/ 這樣做有幾個原因。首先,節省內存。可以放置不可變的字串String Pool
,並且每次都可以使用相同的字串,而不是建立新的字串。其次,安全。例如,任何程式中的大多數登入名稱和密碼都是字串。更改它們的可能性可能會導致授權問題。還有其他原因,但我們在學習 Java 時還沒有觸及它們——我們稍後會回來。
GO TO FULL VERSION