惊!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知识体系学习、分享面试经验,让我们结伴而行,共同成长!

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