java面試題03
1、一個”.java”源文件中是否可以包含多個類(不是內部類)?有什麽限制?
一個".java"源文件中是否可以包括多個類(不是內部類)?有什麽限制?
這個是可以的,一個“.java”源文件裏面可以包含多個類,但是只允許有一個public類,並且類名必須和文件名一致。
每個編譯單元只能有一個public 類。這麽做的意思是,每個編譯單元只能有一個公開的接口,而這個接口就由其public 類來表示。
你可以根據需要,往這個文件裏面添加任意多個提供輔助功能的package 權限的類。但是如果這個編譯單元裏面有兩個或兩個以上的public 類的話,程序就不知道從哪裏導入了,編譯器就會報錯。
2、switch能否作用在byte上,能否作用在long上,能否作用在String上?
switch語句中的表達式只能是byte,short,char ,int以及枚舉(enum),所以當表達式是byte的時候可以隱含轉換為int類型,而long字節比int字節多,不能隱式轉化為int類型,所以switch語句可以用在byte上而不可以用在long上,另外由於在JDK7.0中引入了新特性,所以witch語句可以接收一個String類型的值,String可以作用在switch語句上
3、說說final、finally、finalize三者的區別。
1.final:如果一個類被final修飾,意味著該類不能派生出新的子類,不能作為父類被繼承。因此一個類不能被聲明為abstract,又被聲明為final。將變量或方法聲明為final。可以保證他們在使用的時候不被改變。其初始化可以在兩個地方:一是其定義的地方,也就是在final變量在定義的時候就對其賦值;二是在構造函數中。這兩個地方只能選其中的一個,要麽在定義的時候給值,要麽在構造函數中給值。被聲明為final的方法也只能使用,不能重寫。
2.finally:在異常處理的時候,提供finally塊來執行任何的清除操作。如果拋出一個異常,那麽相匹配的catch字句就會執行,然後控制就會進入finally塊,前提是有finally塊。
3.finalize:finalize是方法名,java技術允許使用finalize()方法在垃圾收集器將對象從內存中清除出去之前做必要的清理工作。這個方法是在垃圾收集器確認一個對象沒有被引用時對這個對象調用的。它是在Object類中定義的,因此,所有的類都繼承了它。子類覆蓋finalize()方法已整理系統資源或者執行其他清理工作。finalize()方法是在垃圾收集器刪除對象之前對這個對象調用的。
4、Math.round(11.5)和Math.round(-11.5)分別等於多少?
Math.round(11.5)的結果是12,Math.round(-11.5)的結果為-11
5、說說String、StringBuffer、StringBuilder的區別。
01、區別
String類型和StringBuffer類型的主要性能區別其實在於String是不可變對象,因此在每次對String類型進行改變的時候其實都等於生成了一個新的String對象,然後將指針指向新的String對象,所以經常改變內容的字符串最好不要用String,因為每次生成對象都會對系統性能產生影響,特別當內存中無引用對象多了以後,JVM的GC就會開始工作,那速度一定會相當慢的。
02、執行速度:
三者在執行速度方面的比較:StringBuilder>StringBuffer>String
03、使用場景:
a、如果要操作少量的數據用String
b、單線程操作字符串緩沖區下操作大量數據 使用StringBuilder
c、多線程操作字符串緩沖區 下 操作大量數據使用 StringBuffer
6、為什麽不建議記錄日誌時使用System.out.println()。
我相信很多的Java新手都非常喜歡使用System.out.println()方法來打印日誌,不知道你是不是也喜歡這麽做。不過在真正的項目開發中,是極度不建議使用System.out.println()方法的!如果你在公司的項目中經常使用這個方法,就很有可能要挨罵了。
為什麽System.out.println()方法會這麽遭大家唾棄呢?經過我仔細分析之後,發現這個方法除了使用方便一點之外,其他就一無是處了。方便在哪兒呢?在Eclipse中你只需要輸入syso,然後按下代碼提示鍵,這個方法就會自動出來了,相信這也是很多Java新手對它鐘情的原因。那缺點又在哪兒了呢?這個就太多了,比如日誌打印不可控制、打印時間無法確定、不能添加過濾器、日誌沒有級別區分……
聽我說了這些,你可能已經不太想用System.out.println()方法了,那麽Log就把上面所說的缺點全部都做好了嗎?雖然談不上全部,但我覺得Log已經做得相當不錯了。我現在就來帶你看看Log和LogCat配合的強大之處。
首先在LogCat中是可以很輕松地添加過濾器的,你可以在圖1.21中看到我們目前所有的過濾器。
7、運行時異常和普通異常有什麽區別?
Java 提供了兩類主要的異常 :runtime exception 和 checked exception 。 checked 異常也就是我們經常遇到的 IO 異常,以及 SQL 異常都是這種異常。 對於這種異常, JAVA 編譯器強制要求我們必需對出現的這些異常進行 catch 。所以,面對這種異常不管我們是否願意,只能自己去寫一大堆 catch 塊去處理可能的異常。
但是另外一種異常: runtime exception ,也稱運行時異常,我們可以不處理。當出現這樣的異常時,總是由虛擬機 接管。比如:我們從來沒有人去處理過 NullPointerException 異常,它就是運行時異常,並且這種異常還是最常見的異常之一。
8、Thread.sleep()和Object.wait()有什麽區別?
1、這兩個方法來自不同的類分別是,sleep來自Thread類,和wait來自Object類。
sleep是Thread的靜態類方法,誰調用的誰去睡覺,即使在a線程裏調用了b的sleep方法,實際上還是a去睡覺,要讓b線程睡覺要在b的代碼中調用sleep。
2、最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其他線程可以使用同步控制塊或者方法。
sleep不出讓系統資源;wait是進入線程等待池等待,出讓系統資源,其他線程可以占用CPU。一般wait不會加時間限制,因為如果wait線程的運行資源不夠,再出來也沒用,要等待其他線程調用notify/notifyAll喚醒等待池中的所有線程,才會進入就緒隊列等待OS分配系統資源。sleep(milliseconds)可以用時間指定使它自動喚醒過來,如果時間不到只能調用interrupt()強行打斷。
Thread.Sleep(0)的作用是“觸發操作系統立刻重新進行一次CPU競爭”。
3、使用範圍:wait,notify和notifyAll只能在同步控制方法或者同步控制塊裏面使用,而sleep可以在任何地方使用
synchronized(x){
x.notify()
//或者wait()
}
4、sleep必須捕獲異常,而wait,notify和notifyAll不需要捕獲異常
9、當一個線程進入一個對象的一個synchronized方法後,其他線程是否可以進入此對象的其他synchronized方法和普通方法?
1.其他方法前是否加了synchronized關鍵字,如果沒加,則能。
2.如果這個方法內部調用了wait,則可以進入其他synchronized方法。
3.如果其他個方法都加了synchronized關鍵字,並且內部沒有調用wait,則不能。
10、如何遍歷HashMap。
public static void main(String[] args) {
Map<String,String> map=new HashMap<String,String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
map.put("4", "value4");
//第一種:普通使用,二次取值
System.out.println("\n通過Map.keySet遍歷key和value:");
for(String key:map.keySet())
{
System.out.println("Key: "+key+" Value: "+map.get(key));
}
//第二種
System.out.println("\n通過Map.entrySet使用iterator遍歷key和value: ");
Iterator map1it=map.entrySet().iterator();
while(map1it.hasNext())
{
Map.Entry<String, String> entry=(Entry<String, String>) map1it.next();
System.out.println("Key: "+entry.getKey()+" Value: "+entry.getValue());
}
//第三種:推薦,尤其是容量大時
System.out.println("\n通過Map.entrySet遍歷key和value");
for(Map.Entry<String, String> entry: map.entrySet())
{
System.out.println("Key: "+ entry.getKey()+ " Value: "+entry.getValue());
}
//第四種
System.out.println("\n通過Map.values()遍歷所有的value,但不能遍歷key");
for(String v:map.values())
{
System.out.println("The value is "+v);
}
}
11、Set中的元素不能重復,用什麽方法來區分是否重復呢?是用==還是用equals?它們有什麽區別?
==和equals()的區別
==是判斷對象的內存地址,s1==s2,s2的引用的對象跟s1是同一個。
Object類的equals 也是判斷對象的內存地址。底層也是用的==。
有一些類復寫了equals(),判斷的是此對象的具體內容
Set裏的元素是不能重復的,元素重復與否是使用equals()方法進行判斷的。
equals()和==方法決定引用值是否指向同一對象equals()在類中被覆蓋,為的是當兩個分離的對象的內容和類型相配的話,返回真值
12、 寫一個方法,計算斐波那契數列(1,1,2,3,5,8,...)第100項的值,方法參數為第N項,
第一百項的值為3736710778780434371
方法:
public long shu(int t){
int d =t-3;
long x=2;
long y=1;
for(int i=0;i<d;i++){
long r=x;
x=x+y;
y=r;
}
return x;
}
@Test
public void ku(){
long u= shu(100);
System.out.println(u);
}
}
13、談談你對java.math.BigDecimal類的認識。
Java中提供了大數字(超過16位有效位)的操作類,即 java.math.BinInteger 類和 java.math.BigDecimal 類,用於高精度計算.
其中 BigInteger 類是針對大整數的處理類,而 BigDecimal 類則是針對大小數的處理類.
BigDecimal 類的實現用到了 BigInteger類,不同的是 BigDecimal 加入了小數的概念.
float和Double只能用來做科學計算或者是工程計算;在商業計算中,對數字精度要求較高,必須使用 BigInteger 類和 BigDecimal 類,它支持任何精度的定點數,可以用它來精確計算貨幣值.
BigDecimal類創建的是對象,不能使用傳統的+、-、*、/等算術運算符直接對其進行數學運算,而必須調用其對應的方法.方法的參數也必須是BigDecimal類型的對象.
構造 BigDecimal 對象常用以下方法:
BigDecimal BigDecimal(double d); //不允許使用
BigDecimal BigDecimal(String s); //常用,推薦使用
static BigDecimal valueOf(double d); //常用,推薦使用
其中,
1. double 參數的構造方法,不允許使用!!!!因為它不能精確的得到相應的值;
2. String 構造方法是完全可預知的: 寫入 new BigDecimal("0.1") 將創建一個 BigDecimal,它正好等於預期的0.1; 因此,通常建議優先使用 String 構造方法;
3. 靜態方法 valueOf(double val) 內部實現,仍是將 double 類型轉為 String 類型; 這通常是將 double(或float)轉化為 BigDecimal 的首選方法;
BigDecimal aDouble =new BigDecimal(1.22);
System.out.println("construct with a double value: " + aDouble);
結果: construct with a doublevalue:1.2199999999999999733546474089962430298328399658203125
BigDecimal aString = new BigDecimal("1.22");
System.out.println("construct with a String value: " + aString);
結果: construct with a String value: 1.22
《詳情:http://blog.csdn.net/jackiehff/article/details/8582449》
14、Java進程間通信的方式有哪些。
(1)管道(Pipe):管道可用於具有親緣關系進程間的通信,允許一個進程和另一個與它有共同祖先的進程之間進行通信。
(2)命名管道(named pipe):命名管道克服了管道沒有名字的限制,除具有管道所具有的功能外,它還允許無親緣關系進程間的通信。
(3)信號(Signal):信號是比較復雜的通信方式,用於通知接受進程有某種事件發生,除了用於進程間通信外,進程還可以發送 信號給進程本身。
(4)消息(Message)隊列:消息隊列是消息的鏈接表,包括Posix消息隊列system V消息隊列。
(5)共享內存:使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。
(6)內存映射(mapped memory):內存映射允許任何多個進程間通信,每一個使用該機制的進程通過把一個共享的文件映射到自己的進程地址空間來實現它。
(7)信號量(semaphore):主要作為進程間以及同一進程不同線程之間的同步手段。
(8)套接口(Socket):更為一般的進程間通信機制,可用於不同機器之間的進程間通信。
15、CSS規則style=”padding:0 0 3px 3px”設置的元素內邊距分別多少。
上右下左
padding:0px 1px 2px 3px 上為0,右為0,下為3,左為3
16、說出HTTP請求的GET和POST方式的區別。
1、GET請求,請求的數據會附加在URL之後,以?分割URL和傳輸數據,多個參數用&連接。URL的編碼格式采用的是ASCII編碼,而不是uniclde,即是說所有的非ASCII字符都要編碼之後再傳輸。
POST請求:POST請求會把請求的數據放置在HTTP請求包的包體中。上面的item=bandsaw就是實際的傳輸數據。
因此,GET請求的數據會暴露在地址欄中,而POST請求則不會。
2、傳輸數據的大小
在HTTP規範中,沒有對URL的長度和傳輸的數據大小進行限制。但是在實際開發過程中,對於GET,特定的瀏覽器和服務器對URL的長度有限制。因此,在使用GET請求時,傳輸數據會受到URL長度的限制。
對於POST,由於不是URL傳值,理論上是不會受限制的,但是實際上各個服務器會規定對POST提交數據大小進行限制,Apache、IIS都有各自的配置
3、安全性
POST的安全性比GET的高。這裏的安全是指真正的安全,而不同於上面GET提到的安全方法中的安全,上面提到的安全僅僅是不修改服務器的數據。
比如,在進行登錄操作,通過GET請求,用戶名和密碼都會暴露再URL上,因為登錄頁面有可能被瀏覽器緩存以及其他人查看瀏覽器的歷史記錄的原因,
此時的用戶名和密碼就很容易被他人拿到了。除此之外,GET請求提交的數據還可能會造成Cross-site request frogery攻擊
17、Servlet的forward和redirect的區別。
重定向:
response.sendRedirect("地址");
a. 頁面地址顯示最終頁面
b. 不可向後傳遞參數
c. 跳到外部站點
服務器轉發:
request.getRequestDispatcher("地址").forward(request, response);
a. 頁面地址顯示請求頁面
b. 可以向後傳遞參數
c. 不可以跳到外部站點
重定向發出兩次請求, 轉發只發一次請求
18、寫一段JDBC查詢oracle數據的代碼。
Connection conn = null;
ResultSet rs = null;
//加載驅動
Clas敏感詞orName("oracle.jdbc.OracleDriver");
//獲得連接
conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl",
"scott",
"tiger");
Statement stat = conn.createStatement();
//sql語句
String sql = "SELECT * FROM emp";
//執行語句獲得結果集
rs = stat.executeQuery(sql);
//遍歷結果集
while(rs.next()){
String name = rs.getString("name");
System.out.println(name);}
//關閉鏈接
conn.close();
19、JDBC中PreparedStatement相比Statement的好處
一.代碼的可讀性和可維護性.
雖然用PreparedStatement來代替Statement會使代碼多出幾行,但這樣的代碼無論從可讀性還是可維護性上來說.
都比直接用Statement的代碼高很多檔次;
二.PreparedStatement盡最大可能提高性能.
每一種數據庫都會盡最大努力對預編譯語句提供最大的性能優化 .因為預編譯語句有可能被重復調用.所以語句在被DB的編譯器編譯後的執行代碼被緩存下來,
那麽下次調用時只要是相同的預編譯語句就不需要編譯,
只要將參數直接傳入編譯過的語句執行代碼中( 相當於一個函數,用就是了,不用重寫一個來實現 )就會得到執行.
三.最重要的一點是極大地提高了安全性.
使用預編譯語句.你傳入的任何內容就不會和原來的語句發生任何匹配的關系
只要全使用預編譯語句,你就用不著對傳入的數據做任何過慮(因為後面傳過來的只作參數用,而不參與編譯,
那就不會對含有sql的語句的參數再編譯一次,而留下sql拼接的安全漏洞
20、選擇自己熟悉的數據庫,寫出下列SQL語句:
建立表library:
create table library if not exists(
id int(10) not null primary key auto-increment comment "id",
age int(10) not null comment"年齡",
sex varchar(20) default "男" comment "性別",
)charset=utf-8 default engine=Innodb;
java面試題03