Java数组为何可接受字符作为索引?代码逻辑解析
咱们一步步拆解这个问题,先从核心概念说起,再逐个捋清楚代码里的疑惑点:
核心概念:字符作为数组索引的本质
在Java中,char类型本质是无符号16位整数,它存储的是字符对应的Unicode编码值(对于ASCII字符来说,就是我们熟悉的ASCII码)。而数组的索引要求是int类型,当你把char作为索引传入时,Java会自动执行隐式类型转换,把char转成对应的int值——说白了,你用字符当索引,本质上还是在用整数定位数组位置,完全符合数组的索引规则。
举个例子:'A'的Unicode值是十进制65,所以ram['A'] = 1等价于ram[65] = 1;'b'的Unicode值是98,ram['b'] = 2就等价于ram[98] = 2。
代码中各疑问点的详细解释
1. 为什么ram.length输出256?
数组的长度是初始化时就固定死的:int[] ram = new int[256]; 这里明确指定了数组长度为256,不管你用什么类型的索引去访问,数组本身的长度都不会改变,所以输出必然是256。
2. 为什么ram['A']输出1?
正如前面所说,'A'会被自动转成十进制65,我们之前已经给ram[65]赋值了1,所以读取这个位置的值自然是1。
3. 为什么ram[065]输出0?
这里踩了一个Java字面量的常见坑:Java中以0开头的整数是八进制数,不是十进制。八进制的065转换成十进制是 6*8 + 5 = 53,而我们并没有给ram[53]赋值(53对应的ASCII字符是'5')。由于Java中int数组初始化时,所有元素的默认值都是0,所以读取ram[53]就会输出0。
如果想表示十进制的65,直接写65就行,别加前导0;要是特意用八进制,一定要注意转换后的十进制值是否符合你的预期。
4. 最后那个for-each循环为什么没输出预期的1和2?
这个循环犯了一个典型的新手错误:for-each循环中的变量i是数组的元素值,不是数组的索引。
原代码:
for (int i : ram) { if(ram[i]>0) System.out.println(ram[i]); }
这里的i会依次取ram[0]、ram[1]、ram[2]……直到ram[255]的值,而这些值绝大多数都是0。当i=0时,你访问的是ram[0](值为0);当i=1时访问ram[1](值为0),根本碰不到我们赋值的ram[65]和ram[98]。
如果要遍历数组找到非零元素,正确的写法应该用普通for循环遍历索引:
for (int idx = 0; idx < ram.length; idx++) { if (ram[idx] > 0) { System.out.println(ram[idx]); } }
这样就能遍历到索引65和98,输出1和2了。
内容的提问来源于stack exchange,提问作者Manoj Kumar

