驚!Java裏面註釋的代碼居然被執行了

背景


最近同事寫的程序報了一個非常神奇的錯,錯誤信息如下:

Error:(6, 28) java: 非法字符: 'uff0c'Error:(6, 19) java: 不是語句Error:(7, 15) java: 需要';'

喊我一起去解決這個問題,看到這個錯誤的時候,我首先去搜"uff0c"這個字符串,居然沒有搜到,然後查看的報錯的代碼位置,發現也是正常的,代碼如下:

Long id = subjectOption.getId();// u000d 如果id爲空則新增,否則爲修改if (id == null) {    s = new SubjectOption();    s.setQuestionnaireCode(subjectInfoDTO.getQuestionnaireCode());    s.setSubjectCode(subjectInfoDTO.getCode());    s.setTypeCode(subjectInfoDTO.getTypeCode());    s.setName(subjectOption.getName());    s.setValue(subjectOption.getValue());    s.setSort(subjectOption.getSort());    subjectOptionMapper.insertSubjectOption(s);} else {    subjectOption.setTypeCode(subjectInfoDTO.getTypeCode());    subjectOptionMapper.updateSubjectOption(subjectOption);}

看上去這是一個很正常的代碼,沒有任何問題,但是報錯位置在這裏,經過我逐行的排查,發現問題出現在第二行的註釋上面,刪掉這行代碼就會沒有任何問題出現,難道是註釋裏面的代碼被執行了嗎?

經過我上網查詢了相關資料,發現原因是Unicode解碼發生在任何詞彙解碼之前。而 \u000d 是一個換行符,因此對註釋進行了終止導致換行符後面的註釋代碼被執行了。爲了證明這一點,我寫了個Demo,代碼如下:

public class Test {    public static void main(String[] args) {        String str = "字符串1";        // u000d str="Hello World!";        System.out.println(str);    }}

執行後結果爲:Hello World!

上面的代碼等效於下面的代碼:

public class Test {    public static void main(String[] args) {        String str = "字符串1";        //        str="Hello World!";        System.out.println(str);    }}

 

上面問題引申出一個概念“Unicode 逃逸

那麼什麼叫Unicode 逃逸

我去 oracle 官網查看了一下 Java 語言規範(JLS 3)相關的解釋,大意如下:Unicode 轉義用於表示僅包含 ASCII 字符的 Unicode 符號。當您需要插入無法在源文件的字符集中表示的字符時,它將派上用場。JLS 3.3節的相關說明,Unicode 轉義包含一個反斜槓字符(\),後跟一個或多個'u'字符和四個十六進制數字。

因此,例子中的 \u000d將被視爲換行符。

爲什麼會有這種機制,有什麼作用

這種機制的好處在於它可以在 ASCII 和任何其他編碼之間來回切換,並且不需要你弄清楚註釋的開始和結束位置!

總結


這種方式體現了Java核心的思想 —— 平臺一致性。

雖然這種處理方式看似很好,其實,它卻帶來了副作用(干擾語義),尤其是在文章或者評論中,我們一定要注意這樣的“特殊字符”帶來的Bug。

原創聲明:本文爲【Java學習提升】原創博文,轉載請註明出處。

本文來源於公衆號:【Java學習提升】 專注於Java領域技術分享,Java知識體系學習、分享面試經驗,讓我們結伴而行,共同成長!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章