1. 2 回 (1927 年) を引くと奇妙な結果が得られるのはなぜですか?
(3623 likes)
次のプログラムを実行すると、プログラムは1秒で区切られた2つの日付文字列を解析して比較します:
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ではないのか(なぜならこれらが欲しいからです) 2 タイム差は1秒)ですが、353?
各日付文字列に 1 秒を追加すると:
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 年末の午前 0 時になると、常に 5 分 52 秒戻ります。したがって、「1927-12-31 23:54:08」は実際には 2 回発生し、Java が後者の時間をローカルの日付と時刻として解析したため、違いが生じているようです。
2. Javaは「参照渡し」ですか、それとも「値渡し」ですか?
(2480 いいね)
私は Java は参照渡しだと常に思っていましたが、そうではないと主張するブログ (このブログなど) をたくさん読みました。それらの違いを理解していないと思います。
説明してもらえますか?
解決策
Javaは常に値渡しを重視してきました。残念ながら、ポインタを参照と呼ぶことにしたため、初心者は常に混乱します。これらの参照も値によって渡されるためです。
3. Java += 演算子についての質問
(2223 likes)
今日まで私は、この例:
i += j;
は単なる略記だと思います:
i = i + j;
しかし、これを行うと:
int i = 5; long j = 8;
ただし、i = i + j; はコンパイルできませんが、i += j; はコンパイルできます。
これは i += j という意味ですが、実際には i = (i の型) (i + j) の略ですか?
解決策
この種の質問をする人は常にいますが、JLS がその答えを持っています。 §15.26.2 複合代入演算子を参照してください。抜粋:
E1 op = 型 E2 の複合代入式は、E1 = (T)((E1) op (E2)) と同等です。ここで、T は E1 の型です。違いは、E1 が 1 回だけ計算されることです。
§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 は非マルチスレッド アプリケーションにより適したものになります。
ハッシュテーブルではnull値とキーは許可されません。 HashMap では、NULL キーと NULL 値が許可されます。
HashMap のサブクラスは LinkedHashMap です。したがって、反復順序 (デフォルトの挿入順序) を予測したい場合は、HashMap を LinkedHashMap に変換するだけです。 Hashtable の場合はそれほど単純ではありません。
同期は問題ないので、HashMap を使用することをお勧めします。同期が問題になる場合は、ConcurrentHashMap も検討してください。
5. (方法) InputStream を読み取るか、String に変換する
(1724 likes)
java.io.InputStream オブジェクトがある場合、このオブジェクトを処理して文字列を生成するにはどうすればよいでしょうか。
テキストデータを含むInputStreamオブジェクトがあり、それを文字列に変換したいとします(たとえば、ストリームの内容をログファイルに書き込むことができるように)。
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 はパスワードに String ではなく char[] を使用することを好むのでしょうか?
(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。
8、(如何)从数组创建ArrayList
(1468个赞)
我有一个数组,初始化如下:
Element[] array = {new Element(1), new Element(2), new Element(3)};
我希望将这个数组转化成一个ArrayList类的对象。
解决方案
new ArrayList<Element>(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来完成这个工作,就没有必要重复制造轮子了。