think in java interview-高级开发人员面试宝典(二)
目錄(?)[+]
從現在開始,以樣題的方式一一列出各種面試題以及點評,考慮到我在前文中說的,對于一些大型的外資型公司,你將會面臨全程英語面試,因此我在文章中也會出現許多全英語樣題。
這些題目來自于各個真實的公司,公司名我就不一一例舉了,是本人一直以來苦心收藏的。
一個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。
舉個例子:
publicclass MyUnit{ ?
privateshort ashort; ?
privatechar achar; ?
privatebyte abyte; ?
privateboolean abool; ?
privatelong along; ?
privatefloat afloat; ?
privatedouble adouble; ?
private Unit aObject; ?
privateint[] ints; ?
private Unit[] units; ?
publicboolean equals(Object o) { ?
if (!(o instanceof Unit)) ?
returnfalse; ?
? ? ? Unit unit = (Unit) o; ?
return unit.ashort == ashort ?
? ? ? ? ? ? ?&& unit.achar == achar ?
? ? ? ? ? ? ?&& unit.abyte == abyte ?
? ? ? ? ? ? ?&& unit.abool == abool ?
? ? ? ? ? ? ?&& unit.along == along ?
? ? ? ? ? ? ?&& Float.floatToIntBits(unit.afloat) == Float ?
? ? ? ? ? ? ? ? ? ? .floatToIntBits(afloat) ?
? ? ? ? ? ? ?&& Double.doubleToLongBits(unit.adouble) == Double ?
? ? ? ? ? ? ? ? ? ? .doubleToLongBits(adouble) ?
? ? ? ? ? ? ?&& unit.aObject.equals(aObject) ?
? ? ? ? ? ? ?&& equalsInts(unit.ints) ?
? ? ? ? ? ? ?&& equalsUnits(unit.units); ?
? ?} ?
privateboolean equalsInts(int[] aints) { ?
return Arrays.equals(ints, aints); ?
? ?} ?
privateboolean equalsUnits(Unit[] aUnits) { ?
return Arrays.equals(units, aUnits); ?
? ?} ?
publicint hashCode() { ?
int result = 17; ?
? ? ? result = 31 * result + (int) ashort; ?
? ? ? result = 31 * result + (int) achar; ?
? ? ? result = 31 * result + (int) abyte; ?
? ? ? result = 31 * result + (abool ? 0 : 1); ?
? ? ? result = 31 * result + (int) (along ^ (along >>> 32)); ?
? ? ? result = 31 * result + Float.floatToIntBits(afloat); ?
long tolong = Double.doubleToLongBits(adouble); ?
? ? ? result = 31 * result + (int) (tolong ^ (tolong >>> 32)); ?
? ? ? result = 31 * result + aObject.hashCode(); ?
? ? ? result = 31 * result + intsHashCode(ints); ?
? ? ? result = 31 * result + unitsHashCode(units); ?
return result; ?
? ?} ?
privateint intsHashCode(int[] aints) { ?
int result = 17; ?
for (int i = 0; i < aints.length; i++) ?
? ? ? ? ? result = 31 * result + aints[i]; ?
return result; ?
? ?} ?
privateint unitsHashCode(Unit[] aUnits) { ?
int result = 17; ?
for (int i = 0; i < aUnits.length; i++) ?
? ? ? ? ? result = 31 * result + aUnits[i].hashCode(); ?
return result; ?
? ?} ?
} ?
當改寫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%的人無法回答或者只回答出一半。
此處考的是編程者在平時開發時是否經??紤]“性能”這個問題。
轉載于:https://blog.51cto.com/longx/1351866
總結
以上是生活随笔為你收集整理的think in java interview-高级开发人员面试宝典(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VBscript.Encode 解码器
- 下一篇: think in java interv