国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

首頁 Java Java入門 深入學習java之transient關鍵字

深入學習java之transient關鍵字

Nov 27, 2019 pm 04:28 PM
java transient 關鍵字

深入學習java之transient關鍵字

對於transient這個關鍵字或許很陌生基本上沒怎麼用過,但是transient關鍵字在java中卻起到了不可或缺的地位!

在學習java的過程中transient關鍵字少見的原因其實離不開它的作用:transient關鍵字的主要作用就是讓某些被transient關鍵字修飾的成員屬性變數(shù)不被序列化。實際上也正是因此,在學習過程中很少用得上序列化操作,一般都是在實際開發(fā)中!至於序列化,相信有很多小白童鞋一直迷迷糊糊或沒有具體的概念,以下這篇文章就介紹一下。

1、何謂序列化?

說起序列化,隨之而來的另一個概念就是反序列化,小白童鞋不要慌,記住了序列化就相當於記住了反序列化,因為反序列化就是序列化反過來,所以部落客建議只記住序列化概念即可,省的搞暈自己。

專業(yè)術語定義的序列化:

Java提供了一個物件序列化的機制。用一個位元組序列可以表示一個對象,該位元組序列包含該對象的資料、對象的類型和對像中儲存的屬性等資訊。位元組序列寫出到檔案之後,相當於檔案中持久保存了一個物件的資訊。反之,該位元組序列還可以從檔案中讀取回來,重構對象,對它進行反序列化。物件的資料、物件的類型和物件中儲存的資料訊息,都可以用來在記憶體中建立物件。

宜春的術語定義序列化:

序列化:位元組—> 物件


深入學習java之transient關鍵字

##其實,我總結的就是上面的結論,如果不理解,直接參照專業(yè)術語的定義,理解之後就記住我的話就行了,記不住,請打死我(我踢m簡直就是天才)

圖理解序列化:啥?你不懂啥是位元組?其實,我在一篇IO流的文章裡就已經(jīng)介紹了序列化,放心,絕對特別詳細~光看文章名字就知道了~

史上最騷最全最詳細的IO流教程,小白都能看懂!

2、為何要序列化?

從上一節(jié)提到序列化的概念,知道概念之後,我們就必須知道 為何要序列化了。

講為何要序列化原因之前,博主我舉個栗子:#就像你去街上買菜,一般操作都是用塑膠袋給包裝起來,直到回家要做飯的時候就把菜拿出來。而這一系列操作就像是極了序列化和反序列化! Java中物件的序列化指的是將物件轉(zhuǎn)換成以位元組序列的形式來表示,這些位元組序列包含了物件的資料和訊息,一個序列化後的物件 可以寫到資料庫或檔案,也可用來 網(wǎng)路傳輸,一般當我們使用 快取cache

(記憶體空間不夠有可能會本地儲存到硬碟)或

遠端呼叫rpc

(網(wǎng)路傳輸)的時候,經(jīng)常需要讓我們的實體類別實作
Serializable

接口,目的就是為了讓其可序列化。  ● 在開發(fā)過程中要使用transient關鍵字修飾的栗子:

如果一個使用者有一些密碼等訊息,為了安全起見,不希望在網(wǎng)路操作中被傳輸,這些資訊對應的變數(shù)就可以加上transient關鍵字。

換句話說,這個欄位的生命週期只存於呼叫者的記憶體而不會寫到磁碟裡持久化。


 ● 在開發(fā)過程中
不需要transient

關鍵字修飾的栗子:

######1、類別中的字段值可以根據(jù)其它字段推導出來。 ###2、看具體業(yè)務需求,哪些字段不想被序列化;#########不知道各位有木有想過為什麼要不被序列化呢?其實主要是為了節(jié)省儲存空間。優(yōu)化程序! ###

PS:記得之前看HashMap原始碼的時候,發(fā)現(xiàn)有個欄位是用transient修飾的,我覺得還是有道理的,確實沒必要對這個modCount字段進行序列化,因為沒有意義,modCount主要用於判斷HashMap是否被修改(像put、remove操作的時候,modCount都會自增),對於這種變量,一開始可以為任何值,0當然也是可以(new出來、反序列化出來、或克隆clone出來的時候都是為0的),沒必要持久化其值。

當然,序列化後的最終目的是為了反序列化,恢復成原先的Java對象,要不然序列化後幹嘛呢,就像買菜一樣,用塑膠袋包裹最後還是為了方便安全到家再去掉塑膠袋,所以序列化後的位元組序列都是可以恢復成Java物件的,這個過程就是反序列化。

3、序列化與transient的使用

#1、#需要做序列化的物件的類,必須實作序列化接口:Java.lang.Serializable 接口(一個標誌接口,沒有任何抽象方法),Java 中大多數(shù)類別都實作了該接口,例如:String,Integer類別等,不實作此介面的類別將不會使任何狀態(tài)序列化或反序列化,會拋NotSerializableException例外。

2、底層會判斷,如果目前物件是 Serializable 的實例,才允許做序列化,Java物件 instanceof Serializable 來判斷。

3、在Java 中使用物件流ObjectOutputStream來完成序列化以及ObjectInputStream流反序列化   

==ObjectOutputStream:透過writeObject()方法做序列化操作== 

==ObjectInputStream:透過readObject() 方法做反序列化操作==

#4、該類別的所有屬性必須是可序列化的。如果有一個屬性不需要可序列化的,則該屬性必須註明是瞬態(tài)的,使用transient 關鍵字修飾。
深入學習java之transient關鍵字
由於位元組嘛所以一定要涉及流的操作,也就是物件流也叫序列化流ObjectOutputstream,下面進行多種狀況分析序列化的操作程式碼!

在這裡,我真的強烈建議看宜春博客的讀者朋友,請試著去敲,切記一眼帶過或複製過去運行就完事了,特別是小白童鞋,相信我!你一定會有不一樣的收穫。千萬不要覺得浪費時間,有時候慢就是快,宜春親身體會!

3.1、沒有實作Serializable介面進行序列化情況

package TransientTest;
import java.io.*;

class UserInfo {  //================================注意這里沒有實現(xiàn)Serializable接口
    private String name;
    private transient String password;

    public UserInfo(String name,String psw) {
        this.name = name;
        this.password=psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) {

        UserInfo userInfo=new UserInfo("老王","123");
        System.out.println("序列化之前信息:"+userInfo);

        try {
            ObjectOutputStream output=new ObjectOutputStream(new FileOutputStream("userinfo.txt"));
            output.writeObject(new UserInfo("老王","123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

運行結果

深入學習java之transient關鍵字

3.2、實作Serializable介面序列化情況

當我們加上實作Serializable介面再運作會發(fā)現(xiàn),專案中出現(xiàn)的userinfo.txt檔案內(nèi)容是這樣的:

深入學習java之transient關鍵字

其實這都不是重點,重點是序列化操作成功了!

3.3、普通序列化情況

package TransientTest;
import java.io.*;

class UserInfo implements Serializable{  //第一步實現(xiàn)Serializable接口
    private String name;
    private String password;//都是普通屬性==============================

    public UserInfo(String name,String psw) {
        this.name = name;
        this.password=psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) throws ClassNotFoundException {

        UserInfo userInfo=new UserInfo("程序員老王","123");
        System.out.println("序列化之前信息:"+userInfo);

        try {
            ObjectOutputStream output=new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步開始序列化操作
            output.writeObject(new UserInfo("程序員老王","123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream input=new ObjectInputStream(new FileInputStream("userinfo.txt"));//第三步開始反序列化操作
            Object o = input.readObject();//ObjectInputStream的readObject方法會拋出ClassNotFoundException
            System.out.println("序列化之后信息:"+o);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

運行結果:

序列化之前信息:UserInfo{name='程序員老王', password='123'}
序列化之后信息:UserInfo{name='程序員老王', password='123'}

3.4、transient序列化情況

#
package TransientTest;
import java.io.*;

class UserInfo implements Serializable{  //第一步實現(xiàn)Serializable接口
    private String name;
    private transient String password; //特別注意:屬性由transient關鍵字修飾===========

    public UserInfo(String name,String psw) {
        this.name = name;
        this.password=psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) throws ClassNotFoundException {

        UserInfo userInfo=new UserInfo("程序員老王","123");
        System.out.println("序列化之前信息:"+userInfo);

        try {
            ObjectOutputStream output=new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步開始序列化操作
            output.writeObject(new UserInfo("程序員老王","123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream input=new ObjectInputStream(new FileInputStream("userinfo.txt"));//第三步開始反序列化操作
            Object o = input.readObject();//ObjectInputStream的readObject方法會拋出ClassNotFoundException
            System.out.println("序列化之后信息:"+o);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

運行結果:

序列化之前信息:UserInfo{name='程序員老王', password='123'}
序列化之后信息:UserInfo{name='程序員老王', password='null'}

特別注意結果,加入transient修飾的屬性值為預設值null!如果被transient修飾的屬性為int型,那它被序列化之後值一定是0,當然各位可以去試試,這能說明什麼呢?說明被標記為transient的屬性在物件被序列化的時候不會被保存(或者說變數(shù)不會持久化)

3.5、static序列化情況

package TransientTest;
import java.io.*;

class UserInfo implements Serializable{  //第一步實現(xiàn)Serializable接口
    private String name;
    private static String password; //特別注意:屬性由static關鍵字修飾==============

    public UserInfo(String name, String psw) {
        this.name = name;
        this.password=psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) throws ClassNotFoundException {

        UserInfo userInfo=new UserInfo("程序員老王","123");
        System.out.println("序列化之前信息:"+userInfo);

        try {
            ObjectOutputStream output=new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步開始序列化操作
            output.writeObject(new UserInfo("程序員老王","123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream input=new ObjectInputStream(new FileInputStream("userinfo.txt"));//第三步開始反序列化操作
            Object o = input.readObject();//ObjectInputStream的readObject方法會拋出ClassNotFoundException
            System.out.println("序列化之后信息:"+o);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

運行結果:

序列化之前信息:UserInfo{name='程序員老王', password='123'}
序列化之后信息:UserInfo{name='程序員老王', password='123'}

這個時候,你就會錯誤的認為static修飾的也被序列化了,其實不然,實際上這裡很容易被搞暈!明明取出null(預設值)就可以說明不會被序列化,這裡明明沒有變成預設值,為何還要說static不會被序列化呢?

實際上,反序列化後類別中static型變數(shù)name的值其實就是目前JVM中對應static變數(shù)的值,這個值是JVM中的並不是反序列化得出的。 也就是說被static修飾的變數(shù)並沒有參與序列化!但咱也不能口說無憑啊,是的,那我們就來看兩個程式對比一下就明白了!

第一個程式:這是一個沒有被static修飾的name屬性程式:

package Thread;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class UserInfo implements Serializable {
    private String name;
    private transient String psw;

    public UserInfo(String name, String psw) {
        this.name = name;
        this.psw = psw;
    }

    public  String getName() {
        return name;
    }

    public  void setName(String name) {
        this.name = name;
    }

    public String getPsw() {
        return psw;
    }

    public void setPsw(String psw) {
        this.psw = psw;
    }

    public String toString() {
        return "name=" + name + ", psw=" + psw;
    }
}
public class TestTransient {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo("程序員老過", "456");
        System.out.println(userInfo);
        try {
            // 序列化,被設置為transient的屬性沒有被序列化
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt"));
            o.writeObject(userInfo);
            o.close();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        try {
            //在反序列化之前改變name的值 =================================注意這里的代碼
            userInfo.setName("程序員老改");
            // 重新讀取內(nèi)容
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt"));
            UserInfo readUserInfo = (UserInfo) in.readObject();
            //讀取后psw的內(nèi)容為null
            System.out.println(readUserInfo.toString());
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

運行結果:

name=程序員老過, psw=456
name=程序員老過, psw=null

從程式執(zhí)行結果可以看出,在反序列化之前試著改變name的值為程式設計師老改,結果是沒有成功的!

第二個程序:這是一個被static修飾的name屬性程序:

package Thread;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class UserInfo implements Serializable {
    private static final long serialVersionUID = 996890129747019948L;
    private static String name;
    private transient String psw;

    public UserInfo(String name, String psw) {
        this.name = name;
        this.psw = psw;
    }

    public  String getName() {
        return name;
    }

    public  void setName(String name) {
        this.name = name;
    }

    public String getPsw() {
        return psw;
    }

    public void setPsw(String psw) {
        this.psw = psw;
    }

    public String toString() {
        return "name=" + name + ", psw=" + psw;
    }
}
public class TestTransient {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo("程序員老過", "456");
        System.out.println(userInfo);
        try {
            // 序列化,被設置為transient的屬性沒有被序列化
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt"));
            o.writeObject(userInfo);
            o.close();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        try {
            //在反序列化之前改變name的值
            userInfo.setName("程序員老改");
            // 重新讀取內(nèi)容
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt"));
            UserInfo readUserInfo = (UserInfo) in.readObject();
            //讀取后psw的內(nèi)容為null
            System.out.println(readUserInfo.toString());
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

運行結果:

name=程序員老過, psw=456
name=程序員老改, psw=null

從程序運行結果中可以看出,在反序列化之前試著改變name的值為程序員老改,結果是成功的!現(xiàn)在對比一下兩個程序是不是就很清晰了?

static關鍵字修飾的成員屬性優(yōu)于非靜態(tài)成員屬性加載到內(nèi)存中,同時靜態(tài)也優(yōu)于對象進入到內(nèi)存中,被static修飾的成員變量不能被序列化,序列化的都是對象,靜態(tài)變量不是對象狀態(tài)的一部分,因此它不參與序列化。所以將靜態(tài)變量聲明為transient變量是沒有用處的。因此,反序列化后類中static型變量name的值實際上是當前JVM中對應static變量的值,這個值是JVM中的并不是反序列化得出的。

如果對static關鍵字還是不太清楚理解的童鞋可以參考這篇文章,應該算是不錯的:深入理解static關鍵字

3.6、final序列化情況

對于final關鍵字來講,final變量將直接通過值參與序列化,至于代碼程序我就不再貼出來了,大家可以試著用final修飾驗證一下!

主要注意的是final 和transient可以同時修飾同一個變量,結果也是一樣的,對transient沒有影響,這里主要提一下,希望各位以后在開發(fā)中遇到這些情況不會滿頭霧水!

4、java類中serialVersionUID作用

既然提到了transient關鍵字就不得不提到序列化,既然提到了序列化,就不得不提到serialVersionUID了,它是啥呢?基本上有序列化就會存在這個serialVersionUID。

深入學習java之transient關鍵字
serialVersionUID適用于Java的序列化機制。簡單來說,Java的序列化機制是通過判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節(jié)流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同就認為是一致的,可以進行反序列化,否則就會出現(xiàn)序列化版本不一致的異常,即是InvalidCastException,在開發(fā)中有時候可寫可不寫,建議最好還是寫上比較好。

5、transient關鍵字小結

1、變量被transient修飾,變量將不會被序列化
2、transient關鍵字只能修飾變量,而不能修飾方法和類。
3、被static關鍵字修飾的變量不參與序列化,一個靜態(tài)static變量不管是否被transient修飾,均不能被序列化。
4、final變量值參與序列化,final transient同時修飾變量,final不會影響transient,一樣不會參與序列化

第二點需要注意的是:本地變量是不能被transient關鍵字修飾的。變量如果是用戶自定義類變量,則該類需要實現(xiàn)Serializable接口

第三點需要注意的是:反序列化后類中static型變量的值實際上是當前JVM中對應static變量的值,這個值是JVM中的并不是反序列化得出的。

結語:被transient關鍵字修飾導致不被序列化,其優(yōu)點是可以節(jié)省存儲空間。優(yōu)化程序!隨之而來的是會導致被transient修飾的字段會重新計算,初始化!

本文來自?java入門?欄目,歡迎學習!

以上是深入學習java之transient關鍵字的詳細內(nèi)容。更多資訊請關注PHP中文網(wǎng)其他相關文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發(fā)現(xiàn)涉嫌抄襲或侵權的內(nèi)容,請聯(lián)絡admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動的應用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Laravel 教程
1600
29
PHP教程
1502
276
如何使用JDBC處理Java的交易? 如何使用JDBC處理Java的交易? Aug 02, 2025 pm 12:29 PM

要正確處理JDBC事務,必須先關閉自動提交模式,再執(zhí)行多個操作,最後根據(jù)結果提交或回滾;1.調(diào)用conn.setAutoCommit(false)以開始事務;2.執(zhí)行多個SQL操作,如INSERT和UPDATE;3.若所有操作成功則調(diào)用conn.commit(),若發(fā)生異常則調(diào)用conn.rollback()確保數(shù)據(jù)一致性;同時應使用try-with-resources管理資源,妥善處理異常並關閉連接,避免連接洩漏;此外建議使用連接池、設置保存點實現(xiàn)部分回滾,並保持事務盡可能短以提升性能。

了解Java虛擬機(JVM)內(nèi)部 了解Java虛擬機(JVM)內(nèi)部 Aug 01, 2025 am 06:31 AM

TheJVMenablesJava’s"writeonce,runanywhere"capabilitybyexecutingbytecodethroughfourmaincomponents:1.TheClassLoaderSubsystemloads,links,andinitializes.classfilesusingbootstrap,extension,andapplicationclassloaders,ensuringsecureandlazyclassloa

如何使用Java的日曆? 如何使用Java的日曆? Aug 02, 2025 am 02:38 AM

使用java.time包中的類替代舊的Date和Calendar類;2.通過LocalDate、LocalDateTime和LocalTime獲取當前日期時間;3.使用of()方法創(chuàng)建特定日期時間;4.利用plus/minus方法不可變地增減時間;5.使用ZonedDateTime和ZoneId處理時區(qū);6.通過DateTimeFormatter格式化和解析日期字符串;7.必要時通過Instant與舊日期類型兼容;現(xiàn)代Java中日期處理應優(yōu)先使用java.timeAPI,它提供了清晰、不可變且線

比較Java框架:Spring Boot vs Quarkus vs Micronaut 比較Java框架:Spring Boot vs Quarkus vs Micronaut Aug 04, 2025 pm 12:48 PM

前形式攝取,quarkusandmicronautleaddueTocile timeProcessingandGraalvSupport,withquarkusoftenpernperforminglightbetterine nosserless notelless centarios.2。

了解網(wǎng)絡端口和防火牆 了解網(wǎng)絡端口和防火牆 Aug 01, 2025 am 06:40 AM

NetworkPortSandFireWallsworkTogetHertoEnableCommunication whereSeringSecurity.1.NetWorkPortSareVirtualendPointSnumbered0-655 35,with-Well-with-Newonportslike80(HTTP),443(https),22(SSH)和25(smtp)sindiessingspefificservices.2.portsoperateervertcp(可靠,c

垃圾收集如何在Java工作? 垃圾收集如何在Java工作? Aug 02, 2025 pm 01:55 PM

Java的垃圾回收(GC)是自動管理內(nèi)存的機制,通過回收不可達對象釋放堆內(nèi)存,減少內(nèi)存洩漏風險。 1.GC從根對象(如棧變量、活動線程、靜態(tài)字段等)出發(fā)判斷對象可達性,無法到達的對像被標記為垃圾。 2.基於標記-清除算法,標記所有可達對象,清除未標記對象。 3.採用分代收集策略:新生代(Eden、S0、S1)頻繁執(zhí)行MinorGC;老年代執(zhí)行較少但耗時較長的MajorGC;Metaspace存儲類元數(shù)據(jù)。 4.JVM提供多種GC器:SerialGC適用於小型應用;ParallelGC提升吞吐量;CMS降

比較Java構建工具:Maven vs. Gradle 比較Java構建工具:Maven vs. Gradle Aug 03, 2025 pm 01:36 PM

Gradleisthebetterchoiceformostnewprojectsduetoitssuperiorflexibility,performance,andmoderntoolingsupport.1.Gradle’sGroovy/KotlinDSLismoreconciseandexpressivethanMaven’sverboseXML.2.GradleoutperformsMaveninbuildspeedwithincrementalcompilation,buildcac

以身作則,解釋說明 以身作則,解釋說明 Aug 02, 2025 am 06:26 AM

defer用於在函數(shù)返回前執(zhí)行指定操作,如清理資源;參數(shù)在defer時立即求值,函數(shù)按後進先出(LIFO)順序執(zhí)行;1.多個defer按聲明逆序執(zhí)行;2.常用於文件關閉等安全清理;3.可修改命名返回值;4.即使發(fā)生panic也會執(zhí)行,適合用於recover;5.避免在循環(huán)中濫用defer,防止資源洩漏;正確使用可提升代碼安全性和可讀性。

See all articles