think in java interview-高级开发人员面试宝典(二)

think in java interview-高级开发人员面试宝典(二)
分类: 面经 18634人阅读 评论(58) 收藏 举报

目录(?)[+]

从现在开始,以样题的方式一一列出各种面试题以及点评,考虑到我在前文中说的,对于一些大型的外资型公司,你将会面临全程英语面试,因此我在文章中也会出现许多全英语样题。

这些题目来自于各个真实的公司,公司名我就不一一例举了,是本人一直以来苦心收藏的。

一个JAVA 的MAIN方法引发的一场血案



Q:    What if the main method is declared as private?

A:     The program compiles properly but at run time it will give "Main method not public." message.



Q: What if the static modifier is removed from the signature of the main method?

A: Program compiles. But at run time throws an error "NoSuchMethodError".


Q: What if I write static public void instead of public static void?

A:  Program compiles and runs properly.



Q: What if I do not provide the String array as the argument to the method?

A:  Program compiles but throws a run time error "NoSuchMethodError".



Q: What is the first argument of the String array in main method?

A:  The String array is empty. It does not have any element. This is unlike C/C++(读作plus plus) where the first element by default is the program name.


Q: If I do not provide any arguments on the command line, then the String array of Main method will be empty or null?

A:  It is empty. But not null.



Q: How can one prove that the array is notnull but empty using one line of code?

A:  Print args.length. It will print 0. That means it is empty. But if it would have been null then it would have thrown a NullPointerException on attempting to print args.length.


仔细看完后有人直接吐血了,拿个eclipse,这几个问题全部模拟一边就可以了,即无算法也不需要死记硬背


有人会说了,唉,我怎么写了5年的JAVA怎么就没记得多写多看,多想想这个public static void main(String[] args)方法呢?唉。。。


再来!!!


hashcode & equals之5重天

何时需要重写equals()


当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念)。



如何覆写equals()和hashcode



覆写equals方法

1  使用instanceof操作符检查“实参是否为正确的类型”。

2  对于类中的每一个“关键域”,检查实参中的域与当前对象中对应的域值。

3. 对于非float和double类型的原语类型域,使用==比较;

4  对于对象引用域,递归调用equals方法;

5  对于float域,使用Float.floatToIntBits(afloat)转换为int,再使用==比较;

6  对于double域,使用Double.doubleToLongBits(adouble)转换为int,再使用==比较;

7  对于数组域,调用Arrays.equals方法。

覆写hashcode


1. 把某个非零常数值,例如17,保存在int变量result中;

2. 对于对象中每一个关键域f(指equals方法中考虑的每一个域):

3, boolean型,计算(f? 0 : 1);

4. byte,char,short型,计算(int);

5. long型,计算(int)(f ^ (f>>>32));

6. float型,计算Float.floatToIntBits(afloat);

7. double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行[2.3];

8. 对象引用,递归调用它的hashCode方法;

9. 数组域,对其中每个元素调用它的hashCode方法。

10. 将上面计算得到的散列码保存到int变量c,然后执行result=37*result+c;

11. 返回result。


举个例子:


[java] view plain copy
  1. publicclass MyUnit{  

  2. privateshort ashort;  

  3. privatechar achar;  

  4. privatebyte abyte;  

  5. privateboolean abool;  

  6. privatelong along;  

  7. privatefloat afloat;  

  8. privatedouble adouble;  

  9. private Unit aObject;  

  10. privateint[] ints;  

  11. private Unit[] units;  

  12. publicboolean equals(Object o) {  

  13. if (!(o instanceof Unit))  

  14. returnfalse;  

  15.       Unit unit = (Unit) o;  

  16. return unit.ashort == ashort  

  17.              && unit.achar == achar  

  18.              && unit.abyte == abyte  

  19.              && unit.abool == abool  

  20.              && unit.along == along  

  21.              && Float.floatToIntBits(unit.afloat) == Float  

  22.                     .floatToIntBits(afloat)  

  23.              && Double.doubleToLongBits(unit.adouble) == Double  

  24.                     .doubleToLongBits(adouble)  

  25.              && unit.aObject.equals(aObject)  

  26.              && equalsInts(unit.ints)  

  27.              && equalsUnits(unit.units);  

  28.    }  

  29. privateboolean equalsInts(int[] aints) {  

  30. return Arrays.equals(ints, aints);  

  31.    }  

  32. privateboolean equalsUnits(Unit[] aUnits) {  

  33. return Arrays.equals(units, aUnits);  

  34.    }  

  35. publicint hashCode() {  

  36. int result = 17;  

  37.       result = 31 * result + (int) ashort;  

  38.       result = 31 * result + (int) achar;  

  39.       result = 31 * result + (int) abyte;  

  40.       result = 31 * result + (abool ? 0 : 1);  

  41.       result = 31 * result + (int) (along ^ (along >>> 32));  

  42.       result = 31 * result + Float.floatToIntBits(afloat);  

  43. long tolong = Double.doubleToLongBits(adouble);  

  44.       result = 31 * result + (int) (tolong ^ (tolong >>> 32));  

  45.       result = 31 * result + aObject.hashCode();  

  46.       result = 31 * result + intsHashCode(ints);  

  47.       result = 31 * result + unitsHashCode(units);  

  48. return result;  

  49.    }  

  50. privateint intsHashCode(int[] aints) {  

  51. int result = 17;  

  52. for (int i = 0; i < aints.length; i++)  

  53.           result = 31 * result + aints[i];  

  54. return result;  

  55.    }  

  56. privateint unitsHashCode(Unit[] aUnits) {  

  57. int result = 17;  

  58. for (int i = 0; i < aUnits.length; i++)  

  59.           result = 31 * result + aUnits[i].hashCode();  

  60. return result;  

  61.    }  

  62. }  





当改写equals()的时候,总是要改写hashCode()


根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode方法,它们仅仅是两个对象。因此,违反了“相等的对象必须具有相等的散列码”。


两个对象如果equals那么这两个对象的hashcode一定相等,如果两个对象的hashcode相等那么这两个对象是否一定equals?

回答是不一定,这要看这两个对象有没有重写Object的hashCode方法和equals方法。如果没有重写,是按Object默认的方式去处理。

试想我有一个桶,这个桶就是hashcode,桶里装的是西瓜我们认为西瓜就是object,有的桶是一个桶装一个西瓜,有的桶是一个桶装多个西瓜。

比如String重写了Object的hashcode和equals,但是两个String如果hashcode相等,那么equals比较肯定是相等的,但是“==”比较却不一定相等。如果自定义的对象重写了hashCode方法,有可能hashcode相等,equals却不一定相等,“==”比较也不一定相等。

此处考的是你对object的hashcode的意义的真正的理解!!!如果作为一名高级开发人员或者是架构师,必须是要有这个概念的,否则,直接ban掉了。

为什么我们在定义hashcode时如: h = 31*h + val[off++];  要使用31这个数呢?
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}

来看一段hashcode的覆写案例:

其实上面的实现也可以总结成数数里面下面这样的公式:

s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]

我们来看这个要命的31这个系数为什么总是在里面乘啊乘的?为什么不适用32或者其他数字?

大家都知道,计算机的乘法涉及到移位计算。当一个数乘以2时,就直接拿该数左移一位即可!选择31原因是因为31是一个素数!

所谓素数:

质数又称素数

素数在使用的时候有一个作用就是如果我用一个数字来乘以这个素数,那么最终的出来的结果只能被素数本身和被乘数还有1来整除!如:我们选择素数3来做系数,那么3*n只能被3和n或者1来整除,我们可以很容易的通过3n来计算出这个n来。这应该也是一个原因!

在存储数据计算hash地址的时候,我们希望尽量减少有同样的hash地址,所谓“冲突”

31是个神奇的数字,因为任何数n * 31就可以被JVM优化为 (n << 5) -n,移位和减法的操作效率要比乘法的操作效率高的多,对左移现在很多虚拟机里面都有做相关优化,并且31只占用5bits!

hashcode & equals基本问到第三问,很多人就已经挂了,如果问到了为什么要使用31比较好呢,90%的人无法回答或者只回答出一半。

此处考的是编程者在平时开发时是否经常考虑“性能”这个问题。



你可能感兴趣的:(java,in,think)