牛客選擇題錯題集

2019-04-26

1. 如下代碼執行的結果顯示是多少( )?

 

A.true,false,truehtml

B.false,true,falsejava

C.true,true,false算法

D.false,false,true設計模式

正確答案: D   你的答案: A (錯誤)數組

解答:緩存

當咱們在爲Integer賦值的時候,java編譯器會將其翻譯成調用valueOf()方法。好比Integer i=127翻譯爲Integer i=Integer.valueOf(127)
而後咱們來看看valueOf()函數的源碼:
1 public static Integer valueOf(int i)
2     {
3         //high爲127
4         if(i >= -128 && i <= IntegerCache.high)
5             return IntegerCache.cache[i + 128];
6         else
7             return new Integer(i);
8     }
能夠看出,對於-128到127之間的數,Java會對其進行緩存。而超出這個範圍則新建一個對象。
因此如今回到這道問題
i1和i2爲128,超出範圍,因此都須要新建對象,對象比較爲false;
i5和i6爲100,在範圍以內,在執行Integer i5=100時,就會直接緩存到內存中,但執行執行Integer i6=100時,就直接從緩存裏取,而不須要新建對象,因此爲true。
IntegerCache的源碼
/**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM class.
     */
 
    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];
 
// 省略
}

能夠看到能夠經過設置虛擬機參數:XX:AutoBoxCacheMax=<size>或 -Djava.lang.Integer.IntegerCache.high=<high>安全

來設置緩存範圍的最大值(包含)ide

這歸結於java對於Integer與int的自動裝箱與拆箱的設計,是一種模式:享元模式(flyweight)函數

爲了加大對簡單數字的重利用,java定義:在自動裝箱時對於值從–128到127之間的值,它們被裝箱爲Integer對象後,會存在內存中被重用,始終只存在一個對象。post

而若是超過了從–128到127之間的值,被裝箱後的Integer對象並不會被重用,即至關於每次裝箱時都新建一個 Integer對象;以上的現象是因爲使用了自動裝箱所引發的,若是你沒有使用自動裝箱,而是跟通常類同樣,用new來進行實例化,就會每次new就都一個新的對象。

享元模式

享元模式(Flyweight Pattern)主要用於減小建立對象的數量,以減小內存佔用和提升性能。這種類型的設計模式屬於結構型模式,它提供了減小對象數量從而改善應用所需的對象結構的方式。

享元模式,換句話說就是共享對象,在某些對象須要重複建立,且最終只須要獲得單一結果的狀況下使用。由於此種模式是利用先前建立的已有對象,經過某種規則去判斷當前所需對象是否能夠利用原有對象作相應修改後獲得想要的效果,如以上教程的實例,建立了20個不一樣效果的圓,但相同顏色的圓只須要建立一次即可,相同顏色的只須要引用原有對象,改變其座標值即可。此種模式下,同一顏色的圓雖然位置不一樣,但其地址都是同一個,因此說此模式適用於結果注重單一結果的狀況。

舉一個簡單例子,一個遊戲中有不一樣的英雄角色,同一類型的角色也有不一樣屬性的英雄,如刺客類型的英雄有不少個,按此種模式設計,利用英雄所屬類型去引用原有同一類型的英雄實例,而後對其相應屬性進行修改,即可獲得最終想獲得的最新英雄;好比說你建立了第一個刺客型英雄,而後須要設計第二個刺客型英雄,你利用第一個英雄改變屬性獲得第二個刺客英雄,最新的刺客英雄是誕生了,但第一個刺客英雄的屬性也隨之變得與第二個相同,這種狀況顯然是不能夠的。

擴展:下面代碼的輸出爲何?

public class Demo{
    public static void main(String[] args){
        String s1 = "100"; 
        String s2 = "100";
        System. out. print((s1==s2)+",");

        String s3 = new String("100"); 
        System. out. print((s2==s3)+",");

        String s4 = new String("100");
        System. out. print((s3==s4)+",");
        }
}      
輸出:
true,false,false,

VM爲了提高性能和減小內存開銷,避免字符串的重複建立,維護了一塊特殊的內存空間——字符串實例池

String賦值的兩種方式。

一、String str = "test";

以這種方式賦值時,JVM會先從字符串實例池中查詢是否存在"test"這個對象,

若是存在,直接把實例池中"test"的地址返回給str。若是不存在,則會在實例池中建立"test"對象,並把該對象的地址返回給str。

二、String str = new String("test");

以這種方式賦值時,JVM會先從字符串實例池中查詢是否存在"test"這個對象,

若不存在則會在實例池中建立"test"對象,同時在堆中建立"test"這個對象,而後將堆中的這個對象的地址返回賦給引用str。

若實例池存在則直接在堆中建立"test"這個對象,而後將堆中的這個對象的地址返回賦給引用str。

上面代碼中的s3和s4分別指向堆中不一樣的地址,因此返回false

 2.下列代碼執行結果爲()

public static void main(String args[])throws InterruptedException{
            Thread t=new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.print("2");
                }
            });
            t.start();
             
            t.join();
            System.out.print("1");
        }
A. 21
B. 12
C. 可能爲12,也可能爲21
D. 以上答案都不對

正確答案: A   你的答案: 空 (錯誤)

thread.Join把指定的線程加入到當前線程,能夠將兩個交替執行的線程合併爲順序執行的線程。好比在線程B中調用了線程A的Join()方法,直到線程A執行完畢後,纔會繼續執行線程B。

t.join();      //使調用線程 t 在此以前執行完畢。 
t.join(1000);  //等待 t 線程,等待時間是1000毫秒

本題在主線程中調用了子線程的join函數,所以主線程必須等待子線程執行完畢才結束所以輸出結果只能是21。

3. jdk1.8中,下面有關java 抽象類和接口的區別,說法錯誤的是?

A. 抽象類能夠有構造方法,接口中不能有構造方法

B. 抽象類中能夠包含非抽象的普通方法,接口中的方法必須是抽象的,不能有非抽象的普通方法

C. 一個類能夠實現多個接口,但只能繼承一個抽象類

D. 接口中能夠有普通成員變量,抽象類中沒有普通成員變量

咱們知道,抽象類是不能被實例化的。但抽象類是否能夠有構造函數?答案是能夠有。抽象類的構造函數用來初始化抽象類的一些字段,而這一切都在抽象類的派生類實例化以前發生。不只如此,抽象類的構造函數還有一種巧妙應用:就是在其內部實現子類必須執行的代碼。

2019-04-27

static 修飾符
靜態變量:

static 關鍵字用來聲明獨立於對象的靜態變量,不管一個類實例化多少對象,它的靜態變量只有一份拷貝。 靜態變量也被稱爲類變量。局部變量不能被聲明爲 static 變量。

靜態方法:

static 關鍵字用來聲明獨立於對象的靜態方法。靜態方法不能使用類的非靜態變量。靜態方法從參數列表獲得數據,而後計算這些數據。

對類變量和方法的訪問能夠直接使用 classname.variablename 和 classname.methodname 的方式訪問。

1. 下列程序執行後結果爲( )

 1 class A {
 2     public int func1(int a, int b) {
 3         return a - b;
 4     }
 5 }
 6 class B extends A {
 7     public int func1(int a, int b) {
 8         return a + b;
 9     }
10 }
11 public class ChildClass {
12     public static void main(String[] args) {
13     A a = new B();
14     B b = new B();
15     System.out.println("Result=" + a.func1(100, 50));
16     System.out.println("Result=" + b.func1(100, 50));
17     }
18 }

正確答案: A   你的答案: C (錯誤)

A. Result=150Result=150

B. Result=100Result=100

C. Result=100Result=150

D. Result=150Result=100

此題考查的是多態。
  對於多態,能夠總結它爲:       

     1、使用父類類型的引用指向子類的對象;

    2、該引用只能調用父類中定義的方法和變量;

    3、若是子類中重寫了父類中的一個方法,那麼在調用這個方法的時候,將會調用子類中的這個方法;(動態鏈接、動態調用)

    4、變量不能被重寫(覆蓋),」重寫「的概念只針對方法,若是在子類中」重寫「了父類中的變量,那麼在編譯時會報錯。

多態的3個必要條件:

        1.繼承   2.重寫   3.父類引用指向子類對象。
向上轉型: Person p = new Man() ; //向上轉型不須要強制類型轉化
向下轉型: Man man = (Man)new Person() ; //必須強制類型轉化

2. BufferedReader的父類是如下哪一個?

正確答案: D   你的答案: D (正確)

A. FilterReader

B. InputStreamReader

C. PipedReader

D. Reader

 

3. 下面代碼將輸出什麼內容:()

1 public class SystemUtil{
2     public static boolean isAdmin(String userId){
3         return userId.toLowerCase()=="admin";
4     }
5     public static void main(String[] args){
6         System.out.println(isAdmin("Admin"));
7     }
8 }

正確答案: B   你的答案: B (正確)

A. true

B. false

C. 1

D. 編譯錯誤

在Java中,String 、Math、還有Integer、Double。。。。等這些封裝類重寫了Object中的equals()方法,讓它再也不比較其對象在內存中的地址,而是比較對象中實際包含的整數的值,即比較的是內容。

=="equals方法:

==操做符專門用來比較兩個變量的值是否相等,也就是用於比較變量所對應的內存中所存儲的數值是否相同,要比較兩個基本類型的數據或兩個引用變量是否相等,只能用==操做符;

若是一個變量指向的數據是對象類型的,那麼,這時候涉及了兩塊內存,對象自己佔用一塊內存(堆內存),變量也佔用一塊內存,例如Objet obj = newObject();變量obj是一個內存,new Object()是另外一個內存,此時,變量obj所對應的內存中存儲的數值就是對象佔用的那塊內存的首地址。對於指向對象類型的變量,若是要比較兩個變量是否指向同一個對象,即要看這兩個變量所對應的內存中的數值是否相等,這時候就須要用==操做符進行比較。

equals方法是用於比較兩個獨立對象的內容是否相同,它比較的兩個對象是獨立的。

若是一個類沒有本身定義equals方法,那麼它將繼承Object類的equals方法,Object類的equals方法的實現代碼以下:

boolean equals(Object o){

return this==o;

}

 

這說明,若是一個類沒有本身定義equals方法,它默認的equals方法(從Object類繼承的)就是使用==操做符,也是在比較兩個變量指向的對象是不是同一對象,這時候使用equals和使用==會獲得一樣的結果,若是比較的是兩個獨立的對象則總返回false。若是你編寫的類但願可以比較該類建立的兩個實例對象的內容是否相同,那麼你必須覆蓋equals方法,由你本身寫代碼來決定在什麼狀況便可認爲兩個對象的內容是相同的。

 

4. 代碼片斷: 

byte b1=1,b2=2,b3,b6; 
final byte b4=4,b5=6; 
b6=b4+b5; 
b3=(b1+b2); 
System.out.println(b3+b6);
關於上面代碼片斷敘述正確的是()

正確答案: C   你的答案: A (錯誤)

A. 輸出結果:13

B.語句:b6=b4+b5編譯出錯

C.語句:b3=b1+b2編譯出錯

D. 運行期拋出異常

被final修飾的變量是常量,這裏的b6=b4+b5能夠當作是b6=10;在編譯時就已經變爲b6=10了
而b1和b2是byte類型,java中進行計算時候將他們提高爲int類型,再進行計算,b1+b2計算後已是int類型,賦值給b3,b3是byte類型,類型不匹配,編譯不會經過,須要進行強制轉換。
Java中的byte,short,char進行計算時都會提高爲int類型

5. 閱讀以下代碼。 請問,對語句行 test.hello(). 描述正確的有()

package NowCoder;
class Test {
    public static void hello() {
        System.out.println("hello");
    }
}
public class MyApplication {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Test test=null;
        test.hello();
    }
}

正確答案: A   你的答案: A (正確)

A.能編譯經過,並正確運行

B.由於使用了未初始化的變量,因此不能編譯經過

C.以錯誤的方式訪問了靜態方法

D.能編譯經過,但因變量爲null,不能正常運行

由於Test類的hello方法是靜態的,因此是屬於類的,當實例化該類的時候,靜態會被優先加載並且只加載一次,因此不受實例化new Test();影響,只要是使用到了Test類,都會加載靜態hello方法!
另外,在其餘類的靜態方法中也是能夠調用公開的靜態方法,此題hello方法是使用public修飾的因此在MyApplication中調用hello也是能夠的。
總結:即便Test test=null;這裏也會加載靜態方法,因此test數據中包含Test類的初始化數據。(靜態的,構造的,成員屬性)
        所以test.hello是會調用到hello方法的。

6. 假設 a 是一個由線程 1 和線程 2 共享的初始值爲 0 的全局變量,則線程 1 和線程 2 同時執行下面的代碼,最終 a 的結果不多是()

boolean isOdd = false;
 
for(int i=1;i<=2;++i)
{
    if(i%2==1)isOdd = trueelse isOdd = false;
    a+=i*(isOdd?1:-1);
}

 

正確答案: D   你的答案: C (錯誤)

A. -1

B. -2

C. 0

D. 1

易知:每一個線程對a 均作了兩次讀寫操做,分別是 「 +1 」 和 「 -2 」
而題目問了是最終a 的結果,因此 a 的結果取決於各自線程對 a 的前後讀寫的順序
結論:a的可能取值爲-一、0、-2
如圖:

 2019-05-11

 

1. 如下程序的輸出結果是

public class Print{
    static boolean out(char c){
        System.out.println(c);
        return true;
    }
    public static void main(String[] argv){
        int i = 0;
        for(out('A');out('B') && (i<2);out('C')){
            i++;
            out('D');
        }
    }
}

正確答案: A   你的答案: A (正確)

A. ABDCBDCB

B. BCDABCD

C. 編譯錯誤

D. 運行錯誤

其實這題考察的是for(int i=0;i<10;i++){}循環的執行順序:
1.int i=0;初始化這一步只執行一次;
2.i<10;進行條件判斷;條件達成返回true 不然false不往下執行,跳出for循環圈
3.i++ ;  是最後執行的,當循環體內的代碼執行完它才進行賦值。

 

2. 若是int x=20, y=5,則語句System.out.println(x+y +""+(x+y)+y);  的輸出結果是()

正確答案: D   你的答案: A (錯誤)

A. 2530

B. 55

C. 2052055

D. 25255

1)不論有什麼運算,小括號的優先級都是最高的,先計算小括號中的運算,獲得x+y +""+25+y
2)任何字符與字符串相加都是字符串,可是是有順序的,字符串前面的按原來的格式相加,字符串後面的都按字符串相加,獲得25+「」+25+5。
x+y+""+(x+y)+y,
先算括號: x+y+""+25+y, 
再按字符串分開看,符串前面的按原來的格式相加,字符串後面的都按字符串相加, x+y+ ""+25+y
獲得  25+""+255
整個再連成字符串 25255
3)上面的結果按字符串相加獲得25255

3. 下列哪一個說法是正確的()

正確答案: D   你的答案: A (錯誤)

A. ConcurrentHashMap使用synchronized關鍵字保證線程安全

B. HashMap實現了Collction接口

C. Array.asList方法返回java.util.ArrayList對象

D. SimpleDateFormat是線程不安全的

A. JDK1.8 的 ConcurrentHashMap 採用CAS+Synchronized保證線程安全。 JDK1.7 及之前採用segment的分段鎖機制實現線程安全,其中segment繼承自ReentrantLock,所以採用Lock鎖來保證線程安全。
B. 
C. Arrays.asList()  返回  java.util.Arrays.ArrayList 對象,這裏的 ArrayList 是 Arrays 私有的內部類
D. 

4. 類Parent和Child定義以下, 將如下哪一種方法插入行5是不合法的(    )

1 class  Parent{
2    public  float  aFun(float a, float b) { }
3 }
4 class  Child  extends  Parent{
5 }

正確答案: A   你的答案: C (錯誤)

A. float aFun(float a, float b){ }

B. public int aFun(int a, int b) { }

C. public float aFun(float p, float q){ }

D. private int aFun(int a, int b){ }

A.方法重寫(覆蓋)。子類方法不能縮小父類方法的訪問權限,錯誤。
B.方法重載。參數列表不一樣,知足重載條件,正確。
C.方法重寫(覆蓋)。方法聲明和父類相同,知足重寫條件,正確。
D.方法重載。參數列表不一樣,知足重載條件,正確
 
 方法重寫(Override)應遵循「兩小一大一相同」原則:
  1. 「兩小」:子類異常小於等於父類,子類返回值小於等於父類;
  2. 「一大」:子類方法的訪問修飾符大於等於父類;
  3. 「一相同」:方法簽名相同。

5. list是一個ArrayList的對象,哪一個選項的代碼填到//todo delete處,能夠在Iterator遍歷的過程當中正確並安全的刪除一個list中保存的對象?()

Iterator it = list.iterator();
int index = 0;
while (it.hasNext())
{
    Object obj = it.next();
    if (needDelete(obj))  //needDelete返回boolean,決定是否要刪除
    {
        //todo delete
    }
    index ++;
}

正確答案: A   你的答案: B (錯誤)

A. it.remove();

B. list.remove(obj);

C. list.remove(index);

D. list.remove(obj,index);

Iterator  支持從源集合中安全地刪除對象,只需在 Iterator 上調用 remove() 便可。這樣作的好處是能夠避免 ConcurrentModifiedException ,當打開 Iterator 迭代集合時,同時又在對集合進行修改。有些集合不容許在迭代時刪除或添加元素,可是調用 Iterator 的remove() 方法是個安全的作法。 

6. 面有關 JAVA 異常類的描述,說法正確的有()

正確答案: A B C   你的答案: A B C (正確)

A. 異常的繼承結構:基類爲 Throwable,Error 和 Exception 實現 Throwable,RuntimeException 和 IOException 等繼承 Exception

B. 非 RuntimeException 通常是外部錯誤(不考慮Error的狀況下),其必須在當前類被 try{}catch 語句塊所捕獲

C. Error 類體系描述了 Java 運行系統中的內部錯誤以及資源耗盡的情形,Error 不須要捕捉

D. RuntimeException 體系包括錯誤的類型轉換、數組越界訪問和試圖訪問空指針等等,必須 被 try{}catch 語句塊所捕獲

ABC

都是Throwable的子類: 
1.Exception(異常) :是程序自己能夠處理的異常。 
2.Error(錯誤): 是程序沒法處理的錯誤。這些錯誤表示故障發生於虛擬機自身、或者發生在虛擬機試圖執行應用時,通常不須要程序處理。

3.檢查異常(編譯器要求必須處置的異常) :  除了Error,RuntimeException及其子類之外,其餘的Exception類及其子類都屬於可查異常。這種異常的特色是Java編譯器會檢查它,也就是說,當程序中可能出現這類異常,要麼用try-catch語句捕獲它,要麼用throws子句聲明拋出它,不然編譯不會經過。

4.非檢查異常(編譯器不要求處置的異常): 包括運行時異常(RuntimeException與其子類)和錯誤(Error)。

14:41:14

1. 下列關於Java語言中String和char的說法,正確的是()

正確答案: C   你的答案: C (正確)

  A. String是Java定義的一種基本數據類型。

  B. String是以「\0」結尾的char類型的數組char[]。

  C. 使用equals()方法比較兩個String是否內容同樣(即字符串中的各個字符都同樣)。

  D. Char類型在Java語言裏面存儲的是ASCII碼。

A 基本數據類型包括byte,short,int,long,float,double,char,boolean,因此A錯。
B,C語言當中是這樣,java不是, String內部是用char[]數組實現的,不過結尾不用\0
C 對,字符串內容比較用equals方法。
D char存儲的unicode碼,不只能夠存儲ascII碼,漢字也能夠。

2. 在java中,不管在何處調用,使用靜態屬性必須以類名作前綴。

正確答案: B   你的答案: A (錯誤)

  A. 正確

  B. 錯誤

1若是是本類使用,能夠直接就用靜態變量名。2若是是其餘類使用,可使用類名來調用,也能夠建立一個實例對象來調用。3若是靜態變量所在的類是靜態類(即靜態內部類,外部類沒有靜態的),那麼無論在本類裏或者在其餘外部類,均可以直接使用靜態變量名

 

3. 下列外部類定義中,不正確的是:( )

正確答案: C   你的答案: D (錯誤)

A. class x { .... }

B. class x extends y { .... }

C. static class x implements y1,y2 { .... }

D. public class x extends Applet { .... }

只有靜態內部類,沒有靜態外部類。static不能用來修飾外部類
4. Math.round(11.5) 等於多少 (). Math.round(-11.5) 等於多少 (  ).

正確答案: C   你的答案: D (錯誤)

A. 11 ,-11

B. 11 ,-12

C. 12 ,-11

D. 12 ,-12

Math類中提供了三個與取整有關的方法:ceil,floor,round 。 ceil 向上取整,Math.ceil(11.3)的結果爲12,Math.ceil(-11.6)的結果爲-11;

                          floor向下取整,Math.floor(11.6)的結果是11,Math.floor(-11.4)的結果-12;

round方法,表示「四捨五入」,算法爲Math.floor(x+0.5),  即將原來的數字加上0.5後再向下取整,因此,Math.round(11.5)的結果是12,Math.round(-11.5)的結果爲-11.

5. 以下代碼,執行test()函數後,屏幕打印結果爲()

public class Test2
{
    public void add(Byte b)
    {
        b = b++;
    }
    public void test()
    {
        Byte a = 127;
        Byte b = 127;
        add(++a);
        System.out.print(a + " ");
        add(b);
        System.out.print(b + "");
    }
}

正確答案: D   你的答案: B (錯誤)

A. 127 127

B. 128 127

C. 129 128

D. 以上都不對

public void add(Byte b){ b=b++; } 這裏涉及java的自動裝包/自動拆包(AutoBoxing/UnBoxing) Byte的首字母爲大寫,是類,看似是引用傳遞,可是 在add函數內實現++操做,會自動拆包成byte值傳遞類型,因此add函數仍是不能實現自增功能。也就是說add函數只是個擺設,沒有任何做用。 Byte類型值大小爲-128~127之間。 add(++a);這裏++a會越界,a的值變爲-128 add(b); 前面說了,add不起任何做用,b仍是127
6. 下面代碼的輸出是什麼?
public class Base
{
    private String baseName = "base";
    public Base()
    {
        callName();
    }
 
    public void callName()
    {
        System. out. println(baseName);
    }
 
    static class Sub extends Base
    {
        private String baseName = "sub";
        public void callName()
        {
            System. out. println (baseName) ;
        }
    }
    public static void main(String[] args)
    {
        Base b = new Sub();
    }
}

正確答案: A   你的答案: B (錯誤)

A. null

B. sub

C. base

 new Sub();在創造派生類的過程當中首先建立基類對象,而後才能建立派生類。
建立基類即默認調用Base()方法,在方法中調用callName()方法,因爲派生類中存在此方法,則被調用的callName()方法是派生類中的方法,此時派生類還未構造,因此變量baseName的值爲null

7. 對 Map 的用法,正確的有:

正確答案: C D   你的答案: B D (錯誤)

A. new java.util.Map().put("key" , "value") ;

B. new java.util.SortedMap().put("key" , "value") ;

C. new java.util.HashMap().put( null , null ) ;

D. new java.util.TreeMap().put( 0 , null ) ;

選C、D。考察的是Map接口實現類的建立對象以及對象類型包含的方法。
A選項Map屬於接口類型,不能夠new的方式建立對象。因此A錯誤。
B選項SortedMap屬於接口類型,不能夠new的方式建立對象。因此B錯誤。
C選項HashMap基於哈希表實現Map接口的類,並容許null的值和null鍵。
D選項TreeMap經過紅黑樹實現Map接口的類,key不能夠爲null,會報NullPointerException異常,value能夠爲null。
public static void main(String[] args) {
        TreeMap<String, Integer> treeMap = new TreeMap<>();
        treeMap.put("0",null);
        System.out.println(treeMap.get("0"));//結果爲:null
    }
相關文章
相關標籤/搜索