Stackoverflow上人氣最旺的10個(gè)Java問(wèn)題
1、為什么兩個(gè)(1927年)時(shí)間相減得到一個(gè)奇怪的結(jié)果?
(3623個(gè)贊)
如果執(zhí)行下面的程序,程序解析兩個(gè)間隔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(因?yàn)槲蚁M@兩個(gè)時(shí)間差是一秒),而是353?
如果將日期字符串各加一秒:
- String str3 = "1927-12-31 23:54:08";
- String str4 = "1927-12-31 23:54:09";
ld4-ld3 的結(jié)果是1.
- sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
- offset=28800000,dstSavings=0,
- useDaylight=false,
- transitions=19,
- lastRule=null]
- Locale(Locale.getDefault()): zh_CN
解決方案
這是上海時(shí)區(qū),在12月31日有一個(gè)變化。
查閱這個(gè)網(wǎng)址來(lái)了解上海在1927年時(shí)區(qū)變化的細(xì)節(jié)。基本上在1927年年底的午夜,始終會(huì)回?fù)?分52秒。所以“1927-12-31 23:54:08”實(shí)際上發(fā)生了兩次,看起來(lái)Java解析了后一次的時(shí)間作為當(dāng)?shù)氐娜掌诤蜁r(shí)間導(dǎo)致了差異。
2、Java是“引用傳遞”還是“值傳遞”?
(2480個(gè)贊)
Java一直是值傳遞。不幸的是,他們決定把指針叫做引用,因此新人總是被搞暈。因?yàn)檫@些引用也是通過(guò)值傳遞的。
3、一個(gè)關(guān)于Java += 操作符的問(wèn)題
(2223贊)
直到今天我認(rèn)為這個(gè)例子:
- i += j;
只是一個(gè)簡(jiǎn)寫(xiě)的:
- i = i + j;
但如果這樣做:
- int i = 5;
- long j = 8;
然而 i = i + j; 沒(méi)法編譯,而 i += j; 就可以編譯。
這意味著i += j;
實(shí)際上是i = (type of i) (i + j)
的簡(jiǎn)寫(xiě)么?
解決方案
總有人問(wèn)這類問(wèn)題,JLS里有答案。參見(jiàn) §15.26.2復(fù)合賦值運(yùn)算符。摘錄:
E1 op= E2 型的復(fù)合賦值表達(dá)式等價(jià)于 E1 = (T)((E1) op (E2)),這里 T 是 E1 的類型,不同的是 E1 只計(jì)算一次。
一個(gè)例子,引自 §15.26.2
[...] 下面的代碼是正確的:
- short x = 3;
- x += 4.6;
x的結(jié)果等于7,因?yàn)樗葍r(jià)于:
- short x = 3;
- x = (short)(x + 4.6);
換句話說(shuō),你的假設(shè)是正確的。
4、HashMap 和 Hashtable 之間的不同?
(1769個(gè)贊)
Java中 HashMap
和 Hashtable的不同是什么?
非多線程應(yīng)用中使用哪個(gè)更有效率?
解決方案
Java 中 HashMap 和 HashTable 有幾個(gè)不同點(diǎn):
-
Hashtable
是同步的,然而HashMap
不是。 這使得HashMap更適合非多線程應(yīng)用,因?yàn)榉峭綄?duì)象通常執(zhí)行效率優(yōu)于同步對(duì)象。 -
Hashtable 不允許 null 值和鍵。HashMap允許有一個(gè) null 鍵和人一個(gè) NULL 值。
-
HashMap的一個(gè)子類是
LinkedHashMap。所以,如果想預(yù)知迭代順序(默認(rèn)的插入順序),只需將HashMap轉(zhuǎn)換成一個(gè)LinkedHashMap。用Hashtable就不會(huì)這么簡(jiǎn)單。
因?yàn)橥綄?duì)你來(lái)說(shuō)不是個(gè)問(wèn)題,我推薦使用HashMap。如果同步成為問(wèn)題,你可能還要看看ConcurrentHashMap。
5、(如何) 讀取或者把一個(gè) InputStream 轉(zhuǎn)成一個(gè) String
(1724個(gè)贊)
如果你有一個(gè) java.io.InputStream 對(duì)象,如處理這個(gè)對(duì)象并生成一個(gè)字符串?
假定我有一個(gè) InputStream
對(duì)象,它包含文本數(shù)據(jù),我希望將它轉(zhuǎn)化成一個(gè)字符串(例如,這樣我可以將流的內(nèi)容寫(xiě)到一個(gè)log文件中)。
InputStream
轉(zhuǎn)化成 String 最簡(jiǎn)單方法是什么?
解決方案
使用 Apache commons IOUtils庫(kù)來(lái)拷貝InputStream到StringWriter是一種
不錯(cuò)的方式,類似這樣:
- 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
- // 注意:不關(guān)閉inputStream,你可以使用 IOUtils.closeQuietly
- String theString = IOUtils.toString(inputStream, encoding);
或者,如果不想混合Stream和Writer,可以使用 ByteArrayOutputStream。
#p#
6、為什么Java中的密碼優(yōu)先使用 char[] 而不是String?
(1574個(gè)贊)
在Swing中,密碼字段有一個(gè)getPassword()(返回 char數(shù)組)方法而不是通常的getText()(返回String)方法。同樣的,我遇到過(guò)一個(gè)建議,不要使用 String 來(lái)處理密碼。
為什么String涉及到密碼時(shí),它就成了一個(gè)安全威脅?感覺(jué)使用char數(shù)組不太方便。
解決方案
String是不可變的。這意味著一旦創(chuàng)建了字符串,如果另一個(gè)進(jìn)程可以進(jìn)行內(nèi)存轉(zhuǎn)儲(chǔ),在GC發(fā)生前,(除了反射)沒(méi)有方法可以清除字符串?dāng)?shù)據(jù)。
使用數(shù)組操作完之后,可以顯式地清除數(shù)據(jù):可以給數(shù)組賦任何值,密碼也不會(huì)存在系統(tǒng)中,甚至垃圾回收之前也是如此。
所以,是的,這是一個(gè)安全問(wèn)題 – 但是即使使用了char數(shù)組,僅僅縮小了了攻擊者有機(jī)會(huì)獲得密碼的窗口,它值針對(duì)制定的攻擊類型。
7、遍歷HashMap的最佳方法
(1504個(gè)贊)
遍歷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
- }
- }
更多請(qǐng)查閱Map。
8、(如何)從數(shù)組創(chuàng)建ArrayList
(1468個(gè)贊)
我有一個(gè)數(shù)組,初始化如下:
- Element[] array = {new Element(1), new Element(2), new Element(3)};
我希望將這個(gè)數(shù)組轉(zhuǎn)化成一個(gè)ArrayList類的對(duì)象。
解決方案
- new ArrayList<Element>(Arrays.asList(array))
9、產(chǎn)生一個(gè)Java的內(nèi)存泄露
(1478個(gè)贊)
我有過(guò)一個(gè)面試,被問(wèn)到如何產(chǎn)生一個(gè)Java內(nèi)存泄露。不用說(shuō),我感到相當(dāng)傻,甚至如何產(chǎn)生一個(gè)的線索都沒(méi)有。
那么怎么才能產(chǎn)生一個(gè)內(nèi)存泄露呢?
解決方案
在純Java中,有一個(gè)很好的方式可以產(chǎn)生真正的內(nèi)存泄露(通過(guò)執(zhí)行代碼使對(duì)象不可訪問(wèn)但仍存在于內(nèi)存中):
-
應(yīng)用產(chǎn)生一個(gè)長(zhǎng)時(shí)間運(yùn)行的線程(或者使用一個(gè)線程池加速泄露)。
-
線程通過(guò)一個(gè)(可選的自定義)類加載器加載一個(gè)類。
-
該類分配大內(nèi)存(例如,new byte[1000000]),賦值給一個(gè)強(qiáng)引用存儲(chǔ)在靜態(tài)字段中,再將它自身的引用存儲(chǔ)到ThreadLocal中。分配額外的內(nèi)存是可選的(泄露類實(shí)例就夠了),但是這樣將加速泄露工作。
-
線程清除所有自定義類的或者類加載器載入的引用。
-
重復(fù)上面步驟。
這樣是有效的,因?yàn)門(mén)hreadLocal持有對(duì)象的引用,對(duì)象持有類的引用,接著類持有類加載器的引用。反過(guò)來(lái),類加載器持有所有已加載類的引用。這會(huì)使泄露變得更加嚴(yán)重,因?yàn)楹芏郕VM實(shí)現(xiàn)的類和類加載都直接從持久帶(permgen)分配內(nèi)存,因而不會(huì)被GC回收。
10、使用Java在一個(gè)區(qū)間內(nèi)產(chǎn)生隨機(jī)整數(shù)數(shù)
(1422個(gè)贊)
我試著使用Java生成一個(gè)隨機(jī)整數(shù),但是隨機(jī)被指定在一個(gè)范圍里。例如,整數(shù)范圍是5~10,就是說(shuō)5是最小的隨機(jī)值,10是最大的。5到10之間的書(shū)也可以是生成的隨機(jī)數(shù)。
解決方案
標(biāo)準(zhǔn)的解決方式(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;
- }
請(qǐng)查看相關(guān)的JavaDoc。在實(shí)踐中,java.util.Random 類總是優(yōu)于 java.lang.Math.random()。
特別是當(dāng)標(biāo)準(zhǔn)庫(kù)里有一個(gè)直接的API來(lái)完成這個(gè)工作,就沒(méi)有必要重復(fù)制造輪子了。
原文鏈接: nolsit 翻譯: ImportNew.com - liken
譯文鏈接: http://www.importnew.com/16841.html