1. String 是最基本的數(shù)據(jù)類型嗎?
不是,String是類,String是不可變的,對String類的任何改變,都會返回一個新的String類對象。
2. java的八大數(shù)據(jù)類型?
整型:byte,short,int,long
字符型:char
浮點型:float,double
boolean型:boolean
3. float f=3.4;是否正確?
不正確,java內(nèi),整數(shù)默認(rèn)是int,浮點默認(rèn)是double,支持向上轉(zhuǎn)型,即int自動轉(zhuǎn)long,float自動轉(zhuǎn)double,但不支持自動向下轉(zhuǎn)型。float f = (float)3.4; float f= 3.4f;都是對的。
4. short s1 = 1; s1 = s1 + 1;有錯嗎?short s1 = 1; s1 += 1;有錯嗎?
第一個有錯,還是那句話,整數(shù)java默認(rèn)是int。s1是short,1是int,相加,向上轉(zhuǎn)型是int,int不能賦值給short,需要強轉(zhuǎn)。s1 = (short) s1 + 1;
第二個沒錯,s1 += 1;其實就是s1 = (short) s1 + 1;
5. int和Integer的區(qū)別?
Integer是int的包裝類,int是基本數(shù)據(jù)類型;Integer默認(rèn)為null,int默認(rèn)為0;
用代碼例子說明。
package test;
public class IntTest {
public static void main(String []args) {
Integer a1 = new Integer(100);
Integer a2 = new Integer(100);
Integer b1 = 100;
Integer b2 = 100;
Integer b3 = 128;
Integer b4 = 128;
int c1 = 100;
int c2 = 100;
//false 原因:兩個對象,內(nèi)存地址不同
System.out.println(a1==a2);
//true 原因:非new的Integer比較時,變量在-128到127之間為true,反之為false
System.out.println(b1==b2);
//false 原因:非new的Integer比較時,變量在-128到127之間為true,反之為false
System.out.println(b3==b4);
//true
System.out.println(c1==c2);
//false 原因:new Integer()指向堆中新建的對象,
//非new的Integer指向java常量池中的對象。內(nèi)存地址不同。
System.out.println(a1==b1);
//true 原因:Integer自動拆包,其實就是int之間的比較
System.out.println(a1==c1);
//true 原因:Integer自動拆包,其實就是int之間的比較
System.out.println(b1==c1);
}
}
需要注意的是java在編譯Integer i = 1;時,會變成 Integer i = Integer.valueOf(1);
以下是Integer.valueOf()的源碼
public static Integer valueOf(int i){
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high){
return IntegerCache.cache[i + (-IntegerCache.low)];
}
return new Integer(i);
}
也就是說非new的Integer范圍是-128到127之間的數(shù),會進(jìn)行緩存,下次不會再new,而是直接從緩存里取。
6. 堆(heap),棧(stack),靜態(tài)區(qū)(static area)的分配?
在網(wǎng)上查完資料之后,總結(jié)如下:
heap區(qū):(存儲的基本單位)
1.保存對象的實例(new創(chuàng)建的對象和數(shù)組),實例屬性,屬性類型,對象本身的類型標(biāo)記。
2.存儲的對象包含一個與之對應(yīng)的class信息。
3.JVM只有一個heap區(qū),被所有的線程共享。
4.一般人為釋放,否則程序結(jié)束時由OS回收。
stack區(qū):(運行的基本單位)
1.stack區(qū)存對象的引用,和基礎(chǔ)數(shù)據(jù)類型。
2.保存一個4個字節(jié)的heap內(nèi)存地址,用來定位該對象引用的實例在heap區(qū)的位置。
3.每個線程都有一個stack區(qū),互相之間不能訪問。
靜態(tài)區(qū)/方法區(qū):
1.被所有線程共享。
2.包含所有class和static變量。
3.初始化的全局變量和初始化的靜態(tài)變量在一個區(qū)域,未初始化的全局變量和未初始化的靜態(tài)變量在一個區(qū)域。
7. 最有效率的方法算出2 乘以8?
位運算:System.out.println(2<<3);即可。其實就是2乘(2的三次方)
2的二進(jìn)制往左移兩位。
2的二進(jìn)制0010,移動之后,1000。換成十進(jìn)制就是16。
8. System.err.println(i-=i+=i-=i+=i-=i--);怎么算?
這類題要記住兩點,
1、i的值都不會在這串運算中改變。
2、從右往左算。
public static void main(String[] args) {
int i = 5;
//i=i-i+i-i+i-(i-1)
//5-5+5-5+5-4
System.out.println(i-=i+=i-=i+=i-=--i);//1
i = 5;
//i=i-i+i*i+i-(i-1)
//5-5+5*5+5-4
System.out.println(i-=i+=i*=i+=i-=--i);//-30
}
9.兩個對象值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對不對?
這個本質(zhì)在考 “x和y是兩個對象,x.equals(y)是true的時候,x和y的hash code一樣嗎?”
答:不對,因為java中的規(guī)定是——
1)如果兩個對象相同(equals 方法返回 true),那么它們的hashCode 值一定要相同;
2)如果兩個對象的 hashCode 相同,它們并不一定相同。
關(guān)鍵就是搞清楚equals判斷的是什么,看源碼。
public boolean equals(Object obj) {
return (this == obj);
}
那么這里引出來 == 和 equals 的區(qū)別了。
如果是基本變量,根本沒有equals方法,就是用 == ,比較的就是內(nèi)容。
如果是new出來的對象,父類是object的這種,==比較地址,equals也比較地址。
如果是java中重寫了equals的類,比較什么就看重寫內(nèi)容了。(一般重寫都是為了比較內(nèi)容)
舉兩個例子。
1)String中equals源碼
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
2)ArrayList的父類AbstractList的源碼
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator e2 = ((List) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
所以,如果非要實現(xiàn)equals 方法返回 true,hashCode還不同的情況,也可以。重寫equals方法。
再舉個例子。
public class Equals {
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof Equals) {
return true;
}
return false;
}
public static void main(String[] args) {
Equals A = new Equals();
Equals B = new Equals();
System.out.println(A.equals(B) == true);//true
System.out.println(A.hashCode());
System.out.println(B.hashCode());
}
}
10.new String()創(chuàng)建了幾個對象這類問題
首先明白創(chuàng)建了幾個對象就是在說把對象放在了幾個地方。
那么一共就倆地方,一個是String池,一個是堆。
然后開始各種String的測試。
定義String,無非兩種。
1)String s1 = "hello";
2)String s2 = new String("hello");
第一種,會先驗證String池中有沒有"hello",有的話s1指向"hello"。沒有的話創(chuàng)建新的"hello"存入String池中并指向"hello"。
第二種,會先驗證String池中有沒有"hello",有的話對String池不做任何操作。沒有的話創(chuàng)建新的"hello"并存入String池中。然后繼續(xù)在堆里創(chuàng)建new String("hello"),并指向它。
11.當(dāng)一個對象被當(dāng)作參數(shù)傳遞到一個方法后,此方法可改變這個對象的屬性,并可返回變化后的結(jié)果,那么這里到底是值傳遞還是引用傳遞?
這個問題,查了資料之后,算是有點想法了。
一點一點來。
先說結(jié)論:java中沒有引用傳遞,只有值傳遞。所以這種情況也是值傳遞。
值傳遞的定義是:方法調(diào)用時,實際參數(shù)把它的值傳遞給對應(yīng)的形式參數(shù),方法執(zhí)行中形式參數(shù)值的改變不影響實際參。
引用傳遞的定義是:也稱為傳地址。方法調(diào)用時,實際參數(shù)的引用(地址,而不是參數(shù)的值)被傳遞給方法中相對應(yīng)的形式參數(shù),在方法執(zhí)行中,對形式參數(shù)的操作實際上就是對實際參數(shù)的操作,方法執(zhí)行中形式參數(shù)值的改變將會影響實際參數(shù)的值。
看了值傳遞的定義后,有了疑問。
問:“這種情況應(yīng)該不是值傳遞吧?違反了值傳遞的定義呀,因為對象的屬性變化了。”
答:“對象屬性改了沒問題,但是傳遞的參數(shù)并不是對象呀,所以它改不改不違反值傳遞?!?br>
問:“傳遞的參數(shù)不是對象,那是啥?”
答:“是對象的引用的一個副本?!?br>
問:“這不還是引用嗎?為啥不是引用傳遞?”
答:“還是看定義,引用傳遞 直接傳地址。這種情況傳的引用,指向地址。所以這是通過傳遞對象引用副本的方式實現(xiàn)了引用傳遞的效果,但是,它是值傳遞?!?/p>
問:“確定是值傳遞的問題可以了,那String對象作為參數(shù)傳遞的話,為什么沒有返回變化后的結(jié)果呢?”
答:“額,那照這么說,Integer,Double等也會有此疑問是吧?”
問:“是的?!?br>
答:“因為,Integer是int的包裝類,Double是double的包裝類,String是char[]的包裝類。對包裝類的值操作實際上是通過對其對用的基本類型操作實現(xiàn)的?!?/p>