think in java interview-高级开发人员面试宝典(二)
目錄(?)[+]
從現(xiàn)在開始,以樣題的方式一一列出各種面試題以及點(diǎn)評(píng),考慮到我在前文中說(shuō)的,對(duì)于一些大型的外資型公司,你將會(huì)面臨全程英語(yǔ)面試,因此我在文章中也會(huì)出現(xiàn)許多全英語(yǔ)樣題。
這些題目來(lái)自于各個(gè)真實(shí)的公司,公司名我就不一一例舉了,是本人一直以來(lái)苦心收藏的。
一個(gè)JAVA 的MAIN方法引發(fā)的一場(chǎng)血案
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.
仔細(xì)看完后有人直接吐血了,拿個(gè)eclipse,這幾個(gè)問(wèn)題全部模擬一邊就可以了,即無(wú)算法也不需要死記硬背
有人會(huì)說(shuō)了,唉,我怎么寫了5年的JAVA怎么就沒記得多寫多看,多想想這個(gè)public static void main(String[] args)方法呢?唉。。。
再來(lái)!!!
hashcode & equals之5重天
何時(shí)需要重寫equals()
當(dāng)一個(gè)類有自己特有的“邏輯相等”概念(不同于對(duì)象身份的概念)。
如何覆寫equals()和hashcode
覆寫equals方法
1 ?使用instanceof操作符檢查“實(shí)參是否為正確的類型”。
2 ?對(duì)于類中的每一個(gè)“關(guān)鍵域”,檢查實(shí)參中的域與當(dāng)前對(duì)象中對(duì)應(yīng)的域值。
3. 對(duì)于非float和double類型的原語(yǔ)類型域,使用==比較;
4 ?對(duì)于對(duì)象引用域,遞歸調(diào)用equals方法;
5 ?對(duì)于float域,使用Float.floatToIntBits(afloat)轉(zhuǎn)換為int,再使用==比較;
6 ?對(duì)于double域,使用Double.doubleToLongBits(adouble)轉(zhuǎn)換為int,再使用==比較;
7 ?對(duì)于數(shù)組域,調(diào)用Arrays.equals方法。
覆寫hashcode
1. 把某個(gè)非零常數(shù)值,例如17,保存在int變量result中;
2. 對(duì)于對(duì)象中每一個(gè)關(guān)鍵域f(指equals方法中考慮的每一個(gè)域):
3, boolean型,計(jì)算(f? 0 : 1);
4. byte,char,short型,計(jì)算(int);
5. long型,計(jì)算(int)(f ^ (f>>>32));
6. float型,計(jì)算Float.floatToIntBits(afloat);
7. double型,計(jì)算Double.doubleToLongBits(adouble)得到一個(gè)long,再執(zhí)行[2.3];
8. 對(duì)象引用,遞歸調(diào)用它的hashCode方法;
9. 數(shù)組域,對(duì)其中每個(gè)元素調(diào)用它的hashCode方法。
10. 將上面計(jì)算得到的散列碼保存到int變量c,然后執(zhí)行result=37*result+c;
11. 返回result。
舉個(gè)例子:
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; ?
? ?} ?
} ?
當(dāng)改寫equals()的時(shí)候,總是要改寫hashCode()
根據(jù)一個(gè)類的equals方法(改寫后),兩個(gè)截然不同的實(shí)例有可能在邏輯上是相等的,但是,根據(jù)Object.hashCode方法,它們僅僅是兩個(gè)對(duì)象。因此,違反了“相等的對(duì)象必須具有相等的散列碼”。
兩個(gè)對(duì)象如果equals那么這兩個(gè)對(duì)象的hashcode一定相等,如果兩個(gè)對(duì)象的hashcode相等那么這兩個(gè)對(duì)象是否一定equals?
回答是不一定,這要看這兩個(gè)對(duì)象有沒有重寫Object的hashCode方法和equals方法。如果沒有重寫,是按Object默認(rèn)的方式去處理。
試想我有一個(gè)桶,這個(gè)桶就是hashcode,桶里裝的是西瓜我們認(rèn)為西瓜就是object,有的桶是一個(gè)桶裝一個(gè)西瓜,有的桶是一個(gè)桶裝多個(gè)西瓜。
比如String重寫了Object的hashcode和equals,但是兩個(gè)String如果hashcode相等,那么equals比較肯定是相等的,但是“==”比較卻不一定相等。如果自定義的對(duì)象重寫了hashCode方法,有可能hashcode相等,equals卻不一定相等,“==”比較也不一定相等。
此處考的是你對(duì)object的hashcode的意義的真正的理解!!!如果作為一名高級(jí)開發(fā)人員或者是架構(gòu)師,必須是要有這個(gè)概念的,否則,直接ban掉了。
為什么我們?cè)诙xhashcode時(shí)如: h = 31*h + val[off++]; ?要使用31這個(gè)數(shù)呢?
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;
}
來(lái)看一段hashcode的覆寫案例:
其實(shí)上面的實(shí)現(xiàn)也可以總結(jié)成數(shù)數(shù)里面下面這樣的公式:
s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]
我們來(lái)看這個(gè)要命的31這個(gè)系數(shù)為什么總是在里面乘啊乘的?為什么不適用32或者其他數(shù)字?
大家都知道,計(jì)算機(jī)的乘法涉及到移位計(jì)算。當(dāng)一個(gè)數(shù)乘以2時(shí),就直接拿該數(shù)左移一位即可!選擇31原因是因?yàn)?1是一個(gè)素?cái)?shù)!
所謂素?cái)?shù):
質(zhì)數(shù)又稱素?cái)?shù)
素?cái)?shù)在使用的時(shí)候有一個(gè)作用就是如果我用一個(gè)數(shù)字來(lái)乘以這個(gè)素?cái)?shù),那么最終的出來(lái)的結(jié)果只能被素?cái)?shù)本身和被乘數(shù)還有1來(lái)整除!如:我們選擇素?cái)?shù)3來(lái)做系數(shù),那么3*n只能被3和n或者1來(lái)整除,我們可以很容易的通過(guò)3n來(lái)計(jì)算出這個(gè)n來(lái)。這應(yīng)該也是一個(gè)原因!
在存儲(chǔ)數(shù)據(jù)計(jì)算hash地址的時(shí)候,我們希望盡量減少有同樣的hash地址,所謂“沖突”。
31是個(gè)神奇的數(shù)字,因?yàn)槿魏螖?shù)n * 31就可以被JVM優(yōu)化為 (n << 5) -n,移位和減法的操作效率要比乘法的操作效率高的多,對(duì)左移現(xiàn)在很多虛擬機(jī)里面都有做相關(guān)優(yōu)化,并且31只占用5bits!
hashcode & equals基本問(wèn)到第三問(wèn),很多人就已經(jīng)掛了,如果問(wèn)到了為什么要使用31比較好呢,90%的人無(wú)法回答或者只回答出一半。
此處考的是編程者在平時(shí)開發(fā)時(shí)是否經(jīng)常考慮“性能”這個(gè)問(wèn)題。
轉(zhuǎn)載于:https://blog.51cto.com/longx/1351866
總結(jié)
以上是生活随笔為你收集整理的think in java interview-高级开发人员面试宝典(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: VBscript.Encode 解码器
- 下一篇: think in java interv