java思考题(二)

1.打印类对象为什么自动调用toString方法
System.out.println()输出时怎么调用了toString呢
System类中的out字段是标准输出流,out是static PrintStream类型的,PrintStream类有println函数,其重载形式有参数是Object的:
public void println(Object o)先的调用print(o) (内部是String.valueOf(o),并以write()方法写入这些值),
再调用println()再调用valueOf()
valueOf()的源码如下
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
所以说在打印一个类对象时会自动调用toString方法,如果是自己写的类要记得覆盖了这个方法。

2.HashSet里的元素不是没有固定顺序的吗,那为什么无论按什么顺序插入执行下面的代码每次结果都是一样的?
public static void main(String[] args)
{
Set s = new HashSet();
s.add(1);
s.add(2);
s.add(3);
ArrayList a = new ArrayList(s);
System.out.print(a);
}
首先要知道HashSet是使用HashMap的KeySet来实现的。然后需要了解HashMap的底层存储原理:
它真正用来做存储的其实是一个2的N次方长度(默认16)的键值对(内部类Entry)数组,将一个Entry的Key值进行hashCode计算,再用计算结果对Entry数组长度求余,将得出的结果为数组下标。储存到数组中的下标位置,如果位置冲突,则将Entry放在上一个Entry的next变量中。类似数组+链表的形式。
(这部分原理可通过参看HashMap源码进一步了解)
了解原理后,那HashMap的迭代顺序便是:
for循环这个Entry数组,注意这里是有序的,输出对应下标的Entry对象即可,当然如果对应下标的Entry有next,则继续输出其next的对象。
答案:如果Set中对象是固定的,那么输出顺序一定是固定的,当然不一定按照你的add时的顺序。
当你在add一个对象时,输出时就可能出现在原来顺序的中间,所以迭代器的顺序也不固定。

我们所了解的所有的HashSet实现都进行了一种优化,即每一项在存储元素本身之外,还存储了元素的散列值。在搜索某个元素时,这种实现通过遍历**中的项,去拿存储在每一项中的散列值与我们想要查找的元素的散列值进行比较,从而选取适当的散列位置。只有在两个元素的散列值相等的情况下,这种实现才会认为这两个元素相等。这种优化是有实际意义的,因为比较散列码相对于比较元素来说,其代价要小得多。 "

Set s1 = new HashSet<>();//根据hash算法排序
Set s2 = new LinkedHashSet<>();//插入顺序
Set s3 = new TreeSet<>();//自然顺序,在这里就是数字从小到大

http://www.codeweblog.com/hashset%E6%95%B4%E6%95%B0%E6%8E%92%E5%BA%8F%E7%9A%84%E5%B0%8F%E6%8A%80%E5%B7%A7/

你可能感兴趣的:(java思考题(二))