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. 行為的多型。同一個型別的引用,被指向不同的物件時,有不同的實現。 - 多型的具體表現----向上造型
--父型別的引用指向子類的物件。
--能造型成為的型別有:父類+所有實現的介面。
--能使用什麼方法,看引用的型別。