文章目录
语法话题
本期的话题如下:
关于该表达式,在类似于C / C++中讨论是没有多大意义的,因为C / C++依赖于实现的硬件结构,不同的环境结果也会不同。不过在Java中,这个结果是固定的,不受其运行的硬件环境与平台所影响。
语法分析
我们可以将表达式解析成两种可能的形式:
- i + (++j)
- (i++) + j
以上的括号不是必须的,这里仅为了清晰起见(后面也是如此)。
我们可以通过程序来测试。
package test;
public class Test {
public static void main(String[] args) {
int i = 10;
int j = 20;
int k = i+++j;
System.out.println("i=" + i);
System.out.println("j=" + j);
System.out.println("k=" + k);
}
}
如果解析为第1种形式,则j的值会增1,如果解析为第2种形式,则i的值会增1,程序运行结果如下:
i=11
j=20
k=30
由运行结果可知,编译器将表达式解析为第2种形式,即:
(i++) + j
最长可能解析原则
编译器对原始输入进行符号解析时,使用最长可能解析原则,也就是说,在解析符号的时候,编译器会尽可能多的去结合有效的符号,例如上面的表达式:
i+++j
“+”与“++”都是有效的符号,但是“+++”不是有效的符号,因此,经过解析后,最终将表达式解析为以下4个符号,即:
- i
- ++
- +
- j
这也就是表达式:
(i++) + j
不过,需要留意的是,最长可能解析原则只会尽力去结合有效的符号,即使这样结合并不符合语法规则。例如表达式:
i--j
如果将其解析为:
i - (-j)
这样是符合语法规则的,不过,因为符号“--”是有效的符号,根据最长可能解析原则,编译器会将其解析为:
i-- j
这当然不符合语法规则,最终也会产生编译错误。
原则使用原因
可是,编译器为何要采用这种原则来解析符号呢?简单的理解就是,如果不使用最长可能解析原则,字符多的有效符号就得不到解析。例如,“--”以“-”为前缀,如果没有这种规则,则总是会解析为两个“-”,而不是“--”。
同样,在转义序列中,也存在类似的情况。例如,八进制转义“\101”,根据最长解析原则,编译器总是会将其解析为“\101”,而不是解析为“\10”与“1”,也不会解析为“\1”,“0”与“1”。而对于“\431”,因为“\431”不是一个有效的八进制转义(有效范围是\0 ~ \377),故编译器会将其解析为“\43”与“1”,而不是“\4”,“3”与“1”。
程序示例:
package test;
public class Test {
public static void main(String[] args) {
// \101是字符A的八进制转义。
System.out.println("\101");
// \43是字符#的八进制转义。
System.out.println("\431");
}
}
程序运行结果如下:
A
#1
问题思考
给定如下的语句:
System.out.println("\101")
根据之前的介绍,八进制转义“\101”不会解析为“\10”与“1”两个字符,也不会解析为“\1”,“0”与“1”三个字符,如果我们期望输出“\10”与“1”两个字符,或是“\1”,“0”与“1”三个字符呢,该怎样调整输出?
原则的例外
不过,为了更好的完成符号的解析,最长可能解析原则有两种例外的情况。
例外1——Unicode转义
当编译器从原始输入中解析Unicode转义时(\uxxxx的格式,其中xxxx为4位十六进制的数值),如果\uxxxx前面存在1个(或奇数个)“\”,则\uxxxx不会转义为对应的Unicode字符,而是保持原始输入内容,接受后续的处理。
package test;
public class Test {
public static void main(String[] args) {
// 根据最长可能解析原则,\u0041会解析为其所转义的Unicode字符(A)。
System.out.println("\u0041");
// 不会使用最长可能解析原则,\\u0041(7个字符)会作为原始输入。
// 在后续的解析中,\\为转义序列,编译器会将其解析为\。
System.out.println("\\u0041");
}
}
程序运行结果如下:
A
\u0041
例外2——类型的一部分
在类型的上下文中,例如:
List<List<Integer>> list = new ArrayList<>();
连续出现的“>”总是会解析为单个大于号字符(作为类型的一部分),而不会作为整体解析为移位运算符“>>”或“>>>”。