下面的程序在計算一個int數組中的元素兩兩之間的差,將這些差置于一個集合中,然后打印該集合的尺寸大小。那么,這個程序將打印出什么呢?
import java.util.*;
public class Differences {
public static void main(String[ ] args) {
int vals[ ] = { 789, 678, 567, 456, 345, 234, 123, 012 };
Set diffs = new HashSet();
for (int i = 0; i < vals.length; i++)
for (int j = i; j < vals.length; j++)
diffs.add(vals[i] - vals[j]);
System.out.println(diffs.size());
}
}
外層循環(huán)迭代數組中的每一個元素,而內層循環(huán)從外層循環(huán)當前迭代到的元素開始迭代到數組中的最后一個元素。因此,這個嵌套的循環(huán)將遍歷數組中每一種可能的兩兩組合。(元素可以與其自身組成一對。)這個嵌套循環(huán)中的每一次迭代都計算了一對元素之間的差(總是正的),并將這個差存儲到了集合中,集合是可以消除重復元素的。因此,本謎題就帶來了一個問題,在由vals數組中的元素結成的對中,有多少的正的差存在呢?
當你仔細觀察程序中的數組時,會發(fā)現其構成模式非常明顯:連續(xù)兩個元素之間的差總是111。因此,兩個元素之間的差是它們在數組之間的偏移量之差的函數。如果兩個元素是相同的,那么它們的差就是0;如果兩個元素是相鄰的,那么它們的差就是111;如果兩個元素被另一個元素分割開了,那么它們的差就是222;以此類推??雌饋聿煌牟畹臄盗颗c元素間不同的距離的數量是相等的,也就是等于數組的尺寸,即8。如果你運行該程序,就會發(fā)現它打印的是14。怎么回事呢?
上面的分析有一個小的漏洞。要想了解清楚這個缺陷,我們可以通過將println語句中的.size()這幾個字符移除掉,來打印出集合中的內容。這么做會產生下面的輸出:
[111,222,446,557,668,113,335,444,779,224,0,333,555,666]
這些數字并非都是111的倍數。在vals數組中肯定有兩個毗鄰的元素的差是113。如果你觀察該數組的聲明,不可能很清楚地發(fā)現原因所在:
int vals[ ] = { 789, 678, 567, 456, 345, 234, 123, 012 };
但是如果你打印數組的內容,你就會看見下面的內容:
[789,678,567,456,345,234,123,10]
為什么數組中的最后一個元素是10而不是12呢?因為以0開頭的整數類型字面常量將被解釋成為八進制數值[JLS 3.10.1]。這個隱晦的結構是從C編程語言那里遺留下來東西,C語言產生于1970年代,那時八進制比現在要通用得多。
一旦你知道了012 == 10,就會很清楚為什么該程序打印出了14:有6個不涉及最后一個元素的的非0差,有7個涉及最后一個元素的非0差,還有0,加在一起正好是14個的差。訂正該程序的方法更加明顯:將八進制整型字面常量012替換為十進制整型字面常量12。如果你這么做了,該程序將打印出我們所期望的8。
本謎題的教訓很簡單:千萬不要在一個整型字面常量的前面加上一個0;這會使它變成一個八進制字面常量。有意識地使用八進制整型字面常量的情況相當少見,你應該對所有的這種特殊用法增加注釋。對語言設計者來說,在決定應該包含什么特性時,應該考慮到其限制條件。當有所遲疑時,應該將它剔除在外。
import java.util.*;
public class Differences {
public static void main(String[ ] args) {
int vals[ ] = { 789, 678, 567, 456, 345, 234, 123, 012 };
Set diffs = new HashSet();
for (int i = 0; i < vals.length; i++)
for (int j = i; j < vals.length; j++)
diffs.add(vals[i] - vals[j]);
System.out.println(diffs.size());
}
}
外層循環(huán)迭代數組中的每一個元素,而內層循環(huán)從外層循環(huán)當前迭代到的元素開始迭代到數組中的最后一個元素。因此,這個嵌套的循環(huán)將遍歷數組中每一種可能的兩兩組合。(元素可以與其自身組成一對。)這個嵌套循環(huán)中的每一次迭代都計算了一對元素之間的差(總是正的),并將這個差存儲到了集合中,集合是可以消除重復元素的。因此,本謎題就帶來了一個問題,在由vals數組中的元素結成的對中,有多少的正的差存在呢?
當你仔細觀察程序中的數組時,會發(fā)現其構成模式非常明顯:連續(xù)兩個元素之間的差總是111。因此,兩個元素之間的差是它們在數組之間的偏移量之差的函數。如果兩個元素是相同的,那么它們的差就是0;如果兩個元素是相鄰的,那么它們的差就是111;如果兩個元素被另一個元素分割開了,那么它們的差就是222;以此類推??雌饋聿煌牟畹臄盗颗c元素間不同的距離的數量是相等的,也就是等于數組的尺寸,即8。如果你運行該程序,就會發(fā)現它打印的是14。怎么回事呢?
上面的分析有一個小的漏洞。要想了解清楚這個缺陷,我們可以通過將println語句中的.size()這幾個字符移除掉,來打印出集合中的內容。這么做會產生下面的輸出:
[111,222,446,557,668,113,335,444,779,224,0,333,555,666]
這些數字并非都是111的倍數。在vals數組中肯定有兩個毗鄰的元素的差是113。如果你觀察該數組的聲明,不可能很清楚地發(fā)現原因所在:
int vals[ ] = { 789, 678, 567, 456, 345, 234, 123, 012 };
但是如果你打印數組的內容,你就會看見下面的內容:
[789,678,567,456,345,234,123,10]
為什么數組中的最后一個元素是10而不是12呢?因為以0開頭的整數類型字面常量將被解釋成為八進制數值[JLS 3.10.1]。這個隱晦的結構是從C編程語言那里遺留下來東西,C語言產生于1970年代,那時八進制比現在要通用得多。
一旦你知道了012 == 10,就會很清楚為什么該程序打印出了14:有6個不涉及最后一個元素的的非0差,有7個涉及最后一個元素的非0差,還有0,加在一起正好是14個的差。訂正該程序的方法更加明顯:將八進制整型字面常量012替換為十進制整型字面常量12。如果你這么做了,該程序將打印出我們所期望的8。
本謎題的教訓很簡單:千萬不要在一個整型字面常量的前面加上一個0;這會使它變成一個八進制字面常量。有意識地使用八進制整型字面常量的情況相當少見,你應該對所有的這種特殊用法增加注釋。對語言設計者來說,在決定應該包含什么特性時,應該考慮到其限制條件。當有所遲疑時,應該將它剔除在外。