Java基礎(chǔ)知識面試題(隨時更新)

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>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容