1. 程式人生 > >2018初級JAVA面試題(一)

2018初級JAVA面試題(一)

1.用java語言寫一個單例模式:
    (單例模式:顧名思義,在程式中只能有該類的一個例項存在。)

(1)單例餓漢模式(惡漢式單例類在類初始化的時候,已經自動例項化)

public class Singleton1 { 
    //私有的預設構造器 
    private Singleton1() {} 
    //已經自行例項化,注意,這裡有final修飾 
    private static final Singleton1 single = new Singleton1(); 
    //靜態工廠方法 
    public static Singleton1 getInstance() { 
        return single;
    } 
}

(2)懶漢模式:(懶漢式單例類在第一次被呼叫的時候,進行例項化)

public class Singleton2{
    //私有化構造器
    private Singleton2(){};
    //注意,這裡沒有final
    private static Singleton2 instance;
    //靜態工廠方法
    public synchronized static Singleton2 getInstance(){
        if(instance==null){
            instance=new Singleton2();
        }
        return instance;
    }
}

    單例模式有以下特點:

  • 單例類只能有一個例項
  • 單例類必須自己建立自己的唯一例項
  • 單例類必須給所有其他物件提供這一例項

2.用java語言實現:給定一個List<String>,將該List中等於某特定字元的元素刪除(不允許另外建立一個新List),如list為[A,B,B,C],刪除值等於"B"的元素,則該list為[A,C]。

public List<String> check(List<String> list){
    //使用迭代器進行遍歷
    //注意,這裡不能使用for迴圈遍歷,因為list.size()是會變的,可能會遺漏元素
    Iterator<String> iterator=list.iterator();
    while(iterator.hasNext()){
        if("B".equals(iterator.next())){
            iterator.remove();
        }
    }
    return list;
}

注意,這裡不能使用for迴圈遍歷,因為list.size()是會變的,可能會遺漏元素

3.用最有效率的方法計算2乘以8(java語言)。

    int num=2;
    num<<=3;

4.(1)short s1=1;  s1=s1+1;  有錯嗎,為什麼?

   (2)short s1=1;  s1+=1;  有錯嗎,為什麼?

   (3)float f=3.4;  有錯嗎,為什麼?

(1)錯誤,java中1的預設型別是int,int型別和short型別相加會預設轉換為int型別進行儲存,而int型別不能賦值給short型別,會報編譯錯誤。

(2)正確,"+="運算子會自動將結果進行型別轉換,轉換為要賦值變數的型別,相當於  s1=(short) s1+1; 

(3)錯誤,java中3.4的預設型別是double,不能直接將double型別賦值為float型別,會報編譯異常。

5.給定一個字串,如  String str="Hello World"  ,寫一個方法,返回該字串的反轉結果。

public String reverse(String str){
    StringBuilder builder=new StringBuilder(str);
    return builder.reverse().toString();
}

補充:如果是單執行緒的情況下,StringBuilder的效率高於StringBuffer,但是StringBuilder在多執行緒情況下是不安全的,而StringBuffer是執行緒安全的。

6.用Java Socket程式設計實現一個多執行緒的回顯(echo)服務端。

服務端: 

public class EchoServer {
    private ServerSocket server;
    public EchoServer()throws IOException{
        System.out.println("正在啟動服務端。。。");
        server=new ServerSocket(8088);
        System.out.println("服務端啟動完成");
    }
    public void start() throws IOException{
        while(true){
            System.out.println("正在等待客戶端連線。。。");
            Socket client=server.accept();
            System.out.println(client.getInetAddress()+"客戶端已連線");
            ClientHandler handler=new ClientHandler(client);
            handler.start();
        }
    }
    public class ClientHandler extends Thread{
        Socket client;
        public ClientHandler(Socket client){
            this.client=client;
        }
        public void run(){
            try {
                InputStreamReader isr=new InputStreamReader(client.getInputStream());
                BufferedReader br=new BufferedReader(isr);
                String msg=br.readLine();
                System.out.println("客戶端"+client.getInetAddress()+"說:"+msg);
				
                PrintWriter pw=new PrintWriter(client.getOutputStream());
                pw.println("服務端已經接受到您發的"+msg);
                pw.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
         }
    }
    public static void main(String[] args) throws IOException{
        EchoServer echoServer=new EchoServer();
        echoServer.start();
    }
}

客戶端:

public class EchoClient {
	public static void main(String[] args) throws IOException{
        System.out.println("正在連線服務端。。。");
        Socket client=new Socket("127.0.0.1",8088);
        System.out.println("服務端連線成功");
        System.out.println("請輸入要傳送的內容:");
        Scanner scan=new Scanner(System.in);
        String msg=scan.nextLine();
        scan.close();
        PrintWriter pw=new PrintWriter(client.getOutputStream());
        pw.println(msg);
        pw.flush();
    
        InputStreamReader isr=new InputStreamReader(client.getInputStream());
        BufferedReader br=new BufferedReader(isr);
        System.out.println(br.readLine());
        pw.close();
        client.close();
    }
}

7.建立執行緒的三種方法。

(1)直接繼承Thread類,重寫run()方法。

(2)實現Runnable介面,實現run()方法。

(3)使用Callable和Future建立執行緒。

8.面向物件的特徵。

(1)抽象。抽象就是忽略一個主題中與當前目標無關的那些方面,以便更充分地注意與當前目標有關的方面。

        包括過程過程抽象和資料抽象。

  • 過程抽象是指,任何一個明確定義的操作都可以抽象為一個實體。
  • 資料抽象是指抽象出資料型別和施加於該型別物件上的操作,並限定了物件的值只能通過使用這些操作修改和觀察。

(2)封裝。是物件和類概念的主要特性。封裝是把過程和資料包圍起來,對資料的訪問只能通過已定義的介面。

面向物件計算始於這個基本概念,即現實世界可以被描繪成一系列完全自治、封裝的物件,這些物件通過一個受保護的介面訪問其他物件。一旦定義了一個物件的特性,則有必要決定這些特性的可見性,即哪些特性對外部世界是可見的,哪些特性用於表示內部狀態。在這個階段定義物件的介面。通常,應禁止直接訪問一個物件的實際表示,而應通過操作介面訪問物件,這稱為資訊隱藏。事實上,資訊隱藏是使用者對封裝性的認識,封裝則為資訊隱藏提供支援。)

封裝保證了模組具有較好的獨立性,使得程式維護修改較為容易。對應用程式的修改僅限於類的內部,因而可以將應用程式修改帶來的影響減少最低限度。

(3)繼承

  • 作用:減少程式碼的重複,提高程式碼的複用性。
  • 通過extends來實現繼承
  • 父類:所有子類所共有的屬性和行為
    子類:子類所特有的屬性和行為
  • 子類繼承父類後,子類具有(子類+父類)所有的屬性和方法
  • 一個父類可以建立多個子類,但一個子類只能有一個父類------單根繼承
  • 繼承具有傳遞性(子類可作其他類的父類)
  • java規定:構造子類之前必須先構造父類。
    --如果在子類構造方法中沒有呼叫父類構造方法,則預設 super() 來呼叫父類的無參構造。
    --如果子類構造方法中自己呼叫了父類的構造方法,則不再預設提供。
  • 父類和子類在例項化時的執行順序:父類的靜態程式碼-->子類的靜態程式碼-->父類的構造方法-->子類的構造方法

(繼承是一種聯結類的層次模型,並且允許和鼓勵類的重用,它提供了一種明確表述共性的方法。物件的一個新類可以從現有的類中派生,這個過程稱為類繼承。新類繼承了原始類的特性,新類稱為原始類的派生類(子類),而原始類稱為新類的基類(父類)。派生類可以從它的基類那裡繼承方法和例項變數,並且類可以修改或增加新的方法使之更適合特殊的需要。這也體現了大自然中一般與特殊的關係。繼承性很好的解決了軟體的可重用性問題。比如說,所有的Windows應用程式都有一個視窗,它們可以看作都是從一個視窗類派生出來的。但是有的應用程式用於文書處理,有的應用程式用於繪圖,這是由於派生出了不同的子類,各個子類添加了不同的特性。 )

(4)多型

  • 多型的意義:
    a.  物件的多型。同一個物件,被造型成為不同的型別時,有不同的功能。
    b.  行為的多型。同一個型別的引用,被指向不同的物件時,有不同的實現。
  • 多型的具體表現----向上造型
    --父型別的引用指向子類的物件。
    --能造型成為的型別有:父類+所有實現的介面。
    --能使用什麼方法,看引用的型別。