(點選上方公眾號,可快速關註)
來源:ImportNew – liken
1、 為什麼兩個(1927年)時間相減得到一個奇怪的結果?
(3623個贊)
如果執行下麵的程式,程式解析兩個間隔1秒的日期字串並比較:
public static void main(String[] args) throws ParseException {
SimpleDateFormat sf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
String str3 = “1927-12-31 23:54:07”;
String str4 = “1927-12-31 23:54:08”;
Date sDt3 = sf.parse(str3);
Date sDt4 = sf.parse(str4);
long ld3 = sDt3.getTime() /1000;
long ld4 = sDt4.getTime() /1000;
System.out.println(ld4-ld3);
}
輸出是:
353
為什麼 ld4-ld3 不是1(因為我希望這兩個時間差是一秒),而是353?
如果將日期字串各加一秒:
String str3 = “1927-12-31 23:54:08”;
String str4 = “1927-12-31 23:54:09”;
ld4-ld3 的結果是1.
sun.util.calendar.ZoneInfo[id=”Asia/Shanghai”,
offset=28800000,dstSavings=0,
useDaylight=false,
transitions=19,
lastRule=null]
Locale(Locale.getDefault()): zh_CN
解決方案
這是上海時區,在12月31日有一個變化。
查閱這個網址來瞭解上海在1927年時區變化的細節。基本上在1927年年底的午夜,始終會回撥5分52秒。所以“1927-12-31 23:54:08”實際上發生了兩次,看起來Java解析了後一次的時間作為當地的日期和時間導致了差異。
2、Java是“取用傳遞”還是“值傳遞”?
(2480個贊)
我一直認為Java是取用傳遞;然而,我看了一堆部落格(例如這篇)聲稱不是這樣的。我認為我沒有理解它們之間的區別。
http://javadude.com/articles/passbyvalue.htm
給個解釋?
解決方案
Java一直是值傳遞。不幸的是,他們決定把指標叫做取用,因此新人總是被搞暈。因為這些取用也是透過值傳遞的。
3、一個關於Java += 運運算元的問題
(2223贊)
直到今天我認為這個例子:
i += j;
只是一個簡寫的:
i = i + j;
但如果這樣做:
int i = 5;
long j = 8;
然而 i = i + j; 沒法編譯,而 i += j; 就可以編譯。
這意味著i += j; 實際上是i = (type of i) (i + j)的簡寫麼?
解決方案
總有人問這類問題,JLS裡有答案。參見 §15.26.2複合賦值運運算元。摘錄:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2
E1 op= E2 型的複合賦值運算式等價於 E1 = (T)((E1) op (E2)),這裡 T 是 E1 的型別,不同的是 E1 只計算一次。
一個例子,引自 §15.26.2
http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2
[…] 下麵的程式碼是正確的:
short x = 3;
x += 4.6;
x的結果等於7,因為它等價於:
short x = 3;
x = (short)(x + 4.6);
換句話說,你的假設是正確的。
4、HashMap 和 Hashtable 之間的不同?
(1769個贊)
Java中 HashMap 和 Hashtable的不同是什麼?
非多執行緒應用中使用哪個更有效率?
解決方案
Java 中 HashMap 和 HashTable 有幾個不同點:
-
Hashtable 是同步的,然而 HashMap不是。 這使得HashMap更適合非多執行緒應用,因為非同步物件通常執行效率優於同步物件。
-
Hashtable 不允許 null 值和鍵。HashMap允許有一個 null 鍵和人一個 NULL 值。
-
HashMap的一個子類是LinkedHashMap。所以,如果想預知迭代順序(預設的插入順序),只需將HashMap轉換成一個LinkedHashMap。用Hashtable就不會這麼簡單。
因為同步對你來說不是個問題,我推薦使用HashMap。如果同步成為問題,你可能還要看看ConcurrentHashMap。
5、(如何) 讀取或者把一個 InputStream 轉成一個 String
(1724個贊)
如果你有一個 java.io.InputStream 物件,如處理這個物件並生成一個字串?
假定我有一個 InputStream 物件,它包含文字資料,我希望將它轉化成一個字串(例如,這樣我可以將流的內容寫到一個log檔案中)。
InputStream 轉化成 String 最簡單方法是什麼?
解決方案
使用 Apache commons IOUtils庫來複製InputStream到StringWriter是一種不錯的方式,類似這樣:
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, encoding);
String theString = writer.toString();
甚至
// NB: does not close inputStream, you can use IOUtils.closeQuietly for that
// 註意:不關閉inputStream,你可以使用 IOUtils.closeQuietly
String theString = IOUtils.toString(inputStream, encoding);
或者,如果不想混合Stream和Writer,可以使用 ByteArrayOutputStream。
6、為什麼Java中的密碼優先使用 char[] 而不是String?
(1574個贊)
在Swing中,密碼欄位有一個getPassword()(傳回 char陣列)方法而不是通常的getText()(傳回String)方法。同樣的,我遇到過一個建議,不要使用 String 來處理密碼。
為什麼String涉及到密碼時,它就成了一個安全威脅?感覺使用char陣列不太方便。
解決方案
String是不可變的。這意味著一旦建立了字串,如果另一個行程可以進行記憶體轉儲,在GC發生前,(除了反射)沒有方法可以清除字串資料。
使用陣列操作完之後,可以顯式地清除資料:可以給陣列賦任何值,密碼也不會存在系統中,甚至垃圾回收之前也是如此。
所以,是的,這是一個安全問題 – 但是即使使用了char陣列,僅僅縮小了了攻擊者有機會獲得密碼的視窗,它值針對制定的攻擊型別。
7、遍歷HashMap的最佳方法
(1504個贊)
遍歷HashMap中元素的最佳方法是什麼?
解決方案
這樣遍歷entrySet:
public static void printMap(Map mp) {
Iterator it = mp.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
System.out.println(pair.getKey() + ” = ” + pair.getValue());
it.remove(); // avoids a ConcurrentModificationException
}
}
更多請查閱Map。
http://docs.oracle.com/javase/7/docs/api/java/util/Map.html
8、(如何)從陣列建立ArrayList
(1468個贊)
我有一個陣列,初始化如下:
Element[] array = {new Element(1), new Element(2), new Element(3)};
我希望將這個陣列轉化成一個ArrayList類的物件。
解決方案
new ArrayList
(Arrays.asList(array))
9、產生一個Java的記憶體洩露
(1478個贊)
我有過一個面試,被問到如何產生一個Java記憶體洩露。不用說,我感到相當傻,甚至如何產生一個的線索都沒有。
那麼怎麼才能產生一個記憶體洩露呢?
解決方案
在純Java中,有一個很好的方式可以產生真正的記憶體洩露(透過執行程式碼使物件不可訪問但仍存在於記憶體中):
-
應用產生一個長時間執行的執行緒(或者使用一個執行緒池加速洩露)。
-
執行緒透過一個(可選的自定義)類載入器載入一個類。
-
該類分配大記憶體(例如,new byte[1000000]),賦值給一個強取用儲存在靜態欄位中,再將它自身的取用儲存到ThreadLocal中。分配額外的記憶體是可選的(洩露類實體就夠了),但是這樣將加速洩露工作。
-
執行緒清除所有自定義類的或者類載入器載入的取用。
-
重覆上面步驟。
這樣是有效的,因為ThreadLocal持有物件的取用,物件持有類的取用,接著類持有類載入器的取用。反過來,類載入器持有所有已載入類的取用。這會使洩露變得更加嚴重,因為很多JVM實現的類和類載入都直接從持久帶(permgen)分配記憶體,因而不會被GC回收。
10、使用Java在一個區間內產生隨機整數數
(1422個贊)
我試著使用Java生成一個隨機整數,但是隨機被指定在一個範圍裡。例如,整數範圍是5~10,就是說5是最小的隨機值,10是最大的。5到10之間的書也可以是生成的隨機數。
解決方案
標準的解決方式(Java1.7 之前)如下:
import java.util.Random;
public static int randInt(int min, int max) {
Random rand;
int randomNum = rand.nextInt((max – min) + 1) + min;
return randomNum;
}
請檢視相關的JavaDoc。在實踐中,java.util.Random 類總是優於 java.lang.Math.random()。
特別是當標準庫裡有一個直接的API來完成這個工作,就沒有必要重覆製造輪子了。
【關於投稿】
如果大家有原創好文投稿,請直接給公號傳送留言。
① 留言格式:
【投稿】+《 文章標題》+ 文章連結
② 示例:
【投稿】《不要自稱是程式員,我十多年的 IT 職場總結》:http://blog.jobbole.com/94148/
③ 最後請附上您的個人簡介哈~
看完本文有收穫?請轉發分享給更多人
關註「ImportNew」,提升Java技能