1.寫一個Java應用程序,從鍵盤輸入兩個數,然后輸出他們的平方值及立方值。
解析:在Java中沒有像C語言那樣有一個專供接受從鍵盤輸入的scanf函數,所以一般的做法是從鍵盤輸入一行字幅,保存到字符串s中,再將字符組成的字符串s轉換成整型數據后返回。
importjava.io.*;
classInputData{//定義從鍵盤輸入數據的類
staticprivateStrings="";
staticpublicvoidinput(){//從鍵盤輸入一行字幅,保存到字符串s中
BufferedReaderbu=newBufferedReader(
newInputStreamReader(System.in)
);
try{//捕獲輸入/輸出異常
s=bu.readLine();
}catch(IOExceptione){
e.printStackTrace();
}
}
staticpublicintgetInt(){//靜態方法可直接用類名調用
input();
returnInteger.parseInt(s);//將字符組成的字符串s轉換為整型數據后返回
}
}
classResult{
voidprint(intd){
System.out.println(d+"的平方:"+d*d);
System.out.println(d+"的立方:"+d*d*d);
}
}
publicclassPrintResult{
publicstaticvoidmain(String[]args){
Resultresult=newResult();
System.out.println("請輸入一個整數:");
inta=InputData,getInt();
result.print(a);
}
}
2.下面語句中共創建了幾個對象?
String s = "a" + "b" + "c" + "d" + "e";
A.沒有創建對象 B.1個對象 C.2個對象 D.5個對象
解析:該語句在class文件中就相當于String s = "abcde"。然后當JVM執行到這一句時,就在String pool里找,如果沒有這個字符串,就會產生1個對象。可以對比源代碼和反編譯代碼如下:
publicclassa{
publicstaticvoidmain(String[]args){
Strings="a"+"b"+"c"+"d"+"e";
System.out.println(a);
}
}
//反編譯如下:
Javacode
Compilefrom"a.java"
publicclassaextendsjava.lang.Object{
publica();
Code:
0:aload_0
1:invokespecial#1;Methodjava/lang/System.out:Ljava/io/printStream;
4:return
publicstaticvoidmain(java.lang.String[]);
Code:
0:ldc#2;//Stringabcde直接是abcde
2:astore_1
3:getstatic#3;//Fieldjava/lang/System.out.Ljava/io/PrintStream;
6:aload_1
7:invokevirtual#4;//Methodjava/io/PrintStream.println:(Ljava/lang/String;)V
10:return
} String的內部結構是通過StringBuilder實現的。所以,沒有生成"ab"、"abc"等對象s引用在堆棧里,肯定不是對象,所以只創建了一個對象"abcde"。
擴展知識1:Constant Pool常量池的概念
在Java編譯好的class文件中,有個區域稱為Constant Pool,它是一個由數組組成的表,類型為cp_info constant_pool[],用來存儲程序中使用的各種常量,包括Class、String、Integer等各種基本的Java數據類型。對于Constant Pool,表的基本通用結構如下:
cp_info{
u1tag;
u1info[];
} tag是一個數字,用來表示存儲的常量類;;info[]根據類型碼tag的不同會發生相應的變化。
擴展知識2:關于String類的說明
(1)String使用private final char value[] 來實現字符串的存儲,也就是說,String對象創建之后,就不能再修改此對象中存儲的字符串內容,就是因為如此,才說String類型是不可變的(immutable),或者是final的。
(2)String類有一個特殊的創建方法,就是使用""雙引號來創建。例如new String("helloworld")世紀創建了兩個String對象,一個是"helloworld"通過""雙引號創建的,另一個是通過new創建的。只不過他們創建的時期不同,一個是編譯期,一個是運行期。
(3)Java對String類型重載了加號(+)操作符,可以直接使用“+”對兩個字符串進行連接。
(4)運行期調用String類的intern()方法可以向String Pool中動態添加對象。
(5)String的創建方法一般有如下幾種:
①直接使用""引號創建;
②使用new String()創建;
③使用new String("helloworld")創建以及其他一些重載構造函數創建;
④使用重載的字符串連接操作符“+”創建。
3.請簡述一下Java反射機制。
解析:Java中的反射是一種強大的工具,它能夠創建靈活的代碼,這些代碼在運行時裝配,無需在組件之間進行鏈接。反射允許在編寫與執行時,使用程序代碼能夠接入裝載到JVM中的類的內部信息,而不是源代碼中選定的類協作的代碼。這使反射成為構建靈活應用的主要工具。需要注意的是,如果使用不當,反射的成本會很高。
Java中的類反射Reflection是Java程序開發語言特征之一,它允許運行中的Java程序對自身進行檢查,或者說“自審”,并能直接操作程序的內部屬性。Java的這一能力在實際應用中也許用的不是很多,但是在其他的程序設計語言中就不存在這一個特性。例如Pascal、C或者C++中就沒有辦法在程序中獲得與函數定義相關的信息。
4.請說明static nested class 和 inner class的不同。
解析:
(1)nested(嵌套)class(一般是C++的說法)
nested class是合成型聚集關系(Composite Aggregation)的另一種表達方式,也就是說,nested class也可以用Aggregation表達出來。但是,nested class更加精確地表達了一種專用的、緊耦合的關系,尤其是在代碼生成時,nested class在Java中映射成inline class。比如,計算機專用開關電源類可以作為計算機類的nested class,但是電池組累就不一定適合作為計算機類的nested class,因為電池組類表述的是一個過于通用的對象,可能還被包含(Aggregation)于模型中的其他設備對象。class A nested in class B,則說明A是一個nested class,一般A是用來完成B中的某種重要功能的。
(2)innner class(一般是Java的說法)
Java內部類與C++嵌套類最大的不同就是在于是否有指向外部的引用上。靜態內部類(inner class)意味著:創建一個static內部類對象,不需要一個外部類對象,不能從一個static內部類的一個對象訪問一個外部類對象。
5.下列程序的輸出結果是什么?
importjava.util.*;
importjava.net.MalformedInputException;
importjava.net.URL;
publicclassTest{
privatestaticfinalString[]URLNAMES={
"http://www.hust.edu.cn",//IPAddress:202.114.0.245
"http://www.tsinghua.edu.cn",//IPAddress:166.111.4.100
"http://admission.ucas.ac.cn/",//IPAddress:210.77.30.83
"http://admission.gucas.ac.cn/",//IPAddress:210.77.30.83
"http://Admission.ucas.ac.cn/",//IPAddress:210.77.30.83
"http://www.amss.ac.cn",//IPAddress:159.226.97.84
};
publicstaticvoidmain(String[]args)throwsMalformedInputException{
Setfavorites=newHashSet();
for(Stringurlnames:URLNAMES){
favorites.add(newURL(urlnames));
}
System.out.println(favorites.size());
}
} A.一定是4 B.一定是5 C.一定是6 D.以上答案都不對(√)
解析:本題在聯網狀態下會輸出4,這是由于URL的equals比對方式。根據equals的文檔說明:如果兩個主機名解析為同一個IP地址,責任為兩個主機相同(即使主機名不等);如果有一個主機名無法解析,但是兩個主機名相等(不區分大小寫),或者兩個主機名都為null,則也認為這兩個主機相同。也就是說,如果兩個URL的IP地址是相同的,那么這兩個URL就是相等的。根據題干:
"http://admission.ucas.ac.cn/",//IP Address:210.77.30.83
"http://admission.gucas.ac.cn/",//IP Address:210.77.30.83
"http://Admission.ucas.ac.cn/",//IP Address:210.77.30.83
上面3個IP地址是相同的,都是210.77.30.83,所以在Set時都把他們當成同一個,答案為4。
如果在斷網時,這些都無法解析成IP地址的,這時就要判斷URL的名字,僅認為名字相同時才是相同的URL。"http://admission.ucas.ac.cn/"與"http://Admission.ucas.ac.cn/"因為不區分大小寫,所以默認為兩者相同,答案為5。
6.Anonymous Inner Class(匿名內部類)是否可以extends(繼承)其他類,是否可以implements(實現)interface(接口)?
解析:匿名內部類不能繼承,但是一個內部類可以作為一個接口,由另一個內部類實現。final類不能因為性能的原因將類定義為final的(除非程序的框架要求)。如果說整個類都是final的,就表明自己不希望從這個類繼承,或者不允許其他任何人采取這種操作。將類定義成final的結果只是進行繼承——沒有更多的限制,而且所有的方法都默認為final,再也不可以覆蓋。
7.String str="2014-04-01 14:00:00",要把這個串編程20140401140000,你會怎么做?
解析:
(1)不用正則表達式的方法(一般印象)
publicstaticvoidmain(String[]args)throwsException{
Stringstr="2014-04-0114:00:00";
str=str.replaceAll("-","");
str=str.replaceAll(":","");
str=str.replaceAll("","");
System.out.println(str);
} (2)采用正則表達式(加分印象)
classRegularExpression{
publicstaticvoidmain(String[]args){
Stringstr="2014-04-0114:00:00";
Stringstr2="";
String[]result=str.split("\\D");
for(inti=0;i System.out.println(result[i]);
str2+=result[i];
}
System.out.println(str2);
}
}
8.寫一個Singleton出來。
答案:Singleton模式的主要作用是保證在Java應用程序中,一個類Class只有一個實例存在。Singleton通常有兩種形式:
第一種形式:
publicclassSingleton{
privateSingleton(){}
privatestaticSingletoninstance=newSingleton();
publicstaticSingletongetInstance(){
returninstance;
}
}
第二種形式:
//不用每次生成對象,只是第一次使用時生成實例,提高了效率
publicclassSingleton{
privatestaticSingletoninstance=null;
publicstaticsynchronizedSingletongetInstance(){
if(instance==null){
instance=newSingleton();
}
returninstance;
}
}
擴展知識:Java設計模式(共23種):
設計模式主要分三個類型:創建型、結構型和行為型。
創建型有:
Singleton,單例模式:保證一個類只有一個實例,并提供一個訪問它的全局訪問點
Abstract Factory,抽象工廠:提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們的具體類。
Factory Method,工廠方法:定義一個用于創建對象的接口,讓子類決定實例化哪一個類,Factory Method使一個類的實例化延遲到了子類。
Builder,建造模式:將一個復雜對象的構建與他的表示相分離,使得同樣的構建過程可以創建不同的表示。
Prototype,原型模式:用原型實例指定創建對象的種類,并且通過拷貝這些原型來創建新的對象。
行為型有:
Iterator,迭代器模式:提供一個方法順序訪問一個聚合對象的各個元素,而又不需要暴露該對象的內部表示。
Observer,觀察者模式:定義對象間一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知自動更新。
Template Method,模板方法:定義一個操作中的算法的骨架,而將一些步驟延遲到子類中,TemplateMethod使得子類可以不改變一個算法的結構即可以重定義該算法得某些特定步驟。
Command,命令模式:將一個請求封裝為一個對象,從而使你可以用不同的請求對客戶進行參數化,對請求排隊和記錄請求日志,以及支持可撤銷的操作。
State,狀態模式:允許對象在其內部狀態改變時改變他的行為。對象看起來似乎改變了他的類。
Strategy,策略模式:定義一系列的算法,把他們一個個封裝起來,并使他們可以互相替換,本模式使得算法可以獨立于使用它們的客戶。
China of Responsibility,職責鏈模式:使多個對象都有機會處理請求,從而避免請求的送發者和接收者之間的耦合關系
Mediator,中介者模式:用一個中介對象封裝一些列的對象交互。
Visitor,訪問者模式:表示一個作用于某對象結構中的各元素的操作,它使你可以在不改變各元素類的前提下定義作用于這個元素的新操作。
Interpreter,解釋器模式:給定一個語言,定義他的文法的一個表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。
Memento,備忘錄模式:在不破壞對象的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。
結構型有:
Composite,組合模式:將對象組合成樹形結構以表示部分整體的關系,Composite使得用戶對單個對象和組合對象的使用具有一致性。
Facade,外觀模式:為子系統中的一組接口提供一致的界面,fa?ade提供了一高層接口,這個接口使得子系統更容易使用。
Proxy,代理模式:為其他對象提供一種代理以控制對這個對象的訪問
Adapter,適配器模式:將一類的接口轉換成客戶希望的另外一個接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些類可以一起工作。
Decrator,裝飾模式:動態地給一個對象增加一些額外的職責,就增加的功能來說,Decorator模式相比生成子類更加靈活。
Bridge,橋模式:將抽象部分與它的實現部分相分離,使他們可以獨立的變化。
Flyweight,享元模式,運用共享技術有效的支持大量細粒度的對象。
推薦一些設計模式的經典文章:
(1)工廠模式:http://www.cnblogs.com/poissonnotes/archive/2010/12/01/1893871.html
(2)建造模式:http://www.cnblogs.com/cbf4life/archive/2010/01/14/1647710.html
(3)工廠方法模式:http://www.cnblogs.com/cbf4life/archive/2009/12/20/1628494.html
(4)原始模型模式:http://blog.csdn.NET/tj19832/article/details/1164167
(5)單例模式:http://cantellow.iteye.com/blog/838473
(6)適配器模式(也叫變壓器模式):http://www.cnblogs.com/wangjq/archive/2012/07/09/2582485.html
(7)橋梁模式:http://blog.csdn.net/ymeng_bupt/article/details/6834406
(8)合成模式:http://blog.csdn.net/yeyhan/article/details/20452223
(9)裝飾模式:http://www.cnblogs.com/god_bless_you/archive/2010/06/10/1755212.html
(10)門面模式:http://www.cnblogs.com/skywang/articles/1375447.html
(11)享元模式:http://blog.csdn.net/wanghao72214/article/details/4046182
(12)代理模式:http://www.cnblogs.com/cbf4life/archive/2010/01/27/1657438.html
(13)責任鏈模式:http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html
(14)命令模式:http://www.cnblogs.com/devinzhang/archive/2012/01/06/2315235.html
(15)解釋器模式:http://www.cnblogs.com/cbf4life/archive/2009/12/17/1626125.html
(16)迭代子模式:http://www.cnblogs.com/java-my-life/archive/2012/05/22/2511506.html
(17)調停者模式:http://www.cnblogs.com/java-my-life/archive/2012/06/20/2554024.html
(18)備忘錄模式:http://www.cnblogs.com/ywqu/archive/2010/01/25/1655581.html
(19)觀察者模式:http://www.cnblogs.com/wangjq/archive/2012/07/12/2587966.html
(20)狀態模式:http://blog.csdn.net/hguisu/article/details/7557252
(21)策略模式:http://www.cnblogs.com/justinw/archive/2007/02/06/641414.html
(22)模板方法模式:http://blog.csdn.net/lenotang/article/details/2911246
(23)訪問者模式:http://blog.csdn.net/xiaoquanhuang/article/details/6311319
9.spring都有哪些特點?為什么要使用Spring?
答案:
(1)Spring的特點:①Spring不同于其他的Framework,它主要提供的是一種管理你的業務對象的方法。②Spring有分層的體系結構,意味著你能選擇僅僅使用它的任何一個獨立的部分,而其他的仍然是用你的相關實現。③它的設計從一開始就是要幫助你編寫易于測試的代碼,Spring是使用測試驅動開發(TDD)工程的理想框架。④Spring不會給你的工程添加其他的框架依賴,同時Spring又可以稱得上是一個一攬子解決方案,提供了一個典型應用所需要的大部分基礎架構。
(2)Spring的使用原因:①Spring能有效地組織你的中間層對象。②Spring能消除在許多工程中常見的對Singleton的過多使用。③通過一種在不同應用程序和項目間一致的方法來處理配置文件,消除各種自定義格式的屬性文件的需要,僅僅需要看看類的JavaBean屬性。Inversion of Control的使用幫助完成了這種簡化。④能夠很容易培養你面向接口而不是面向的習慣。⑤Spring的設計會讓你使用它創建的應用盡可能少的依賴于他的APIs,在Spring應用中的大多數業務對象沒有依賴于Spring。⑥使用Spring構建的應用程序易于單元測試。⑦Spring使EJB成為一個實現選擇,而不是必需的選擇。你可以用POJOs或者local EJBs來實現業務接口,卻不會影響到調用代碼。⑧Spring提供一些Web應用上的EJB的替代方案,比如用AOP提供聲明性事務管理。⑨Spring為數據存儲提供了一個一致的框架,不論是使用JDBC還是O/R mapping的產品。
10.hibernate工作原理是什么?為什么要使用hibernate?
解析:hibernate可以理解為是一個中間件,負責把Java程序的SQL語句接收過來并發送到數據庫,而數據庫返回來的信息由hibernate接收后直接生成一個對象傳給Java。
答案:
hibernate的工作原理如下:①讀取并解析配置文件。②讀取并解析映射信息,創建SessionFactory。③打開Session。④創建事務Transaction。⑤持久化操作。⑥提交事務。⑦關閉Session。⑧關閉sessionFactory。
使用hibernate的原因如下:①對JDBC訪問數據庫的代碼做了封裝,大大簡化了數據庫訪問層繁瑣的重復性代碼。②hibernate是一個基于JDBC的主流持久化框架,是一個優秀的ORM實現,在很大程度上簡化了DAO層的編碼工作。③hibernate使用Java反射機制,而不是字節碼增強程序來實現透明性。④hibernate的性能非常好,因為它是一個輕量級框架,映射的靈活性很出色。它支持各種關系型數據庫,從一對一到多對多的各種復雜關系。
11.當你編譯和運行下面的代碼時,會出現下面的那種情況?
[java]view plaincopy

publicclassOutter{
staticbooleanaaa;
publicstaticvoidmain(String[]args){
System.out.println(aaa);
}
} A.編譯時錯誤 B.編譯通過并輸出結果false
C.編譯通過并輸出結果true D.編譯通過并輸出結果null
解析:定義在雷尼面的變量會被賦予一個默認的值(初始化),而布爾值個默認初始值是false,因此選B。
12.Which of the choices below correctly describes the amount of time used by the following code?
[java]view plaincopy

n=10;
for(i=1;ifor(j=1;jfor(k=1;kx+=2;
A.O(n^3) B.O(n^2 log n) C.O(n(log n)*2) D.(n log n)(√)
解析:一般來說,要選擇時間復雜度量級較低的算法。
T(n)=O(f(n))
O(1)
13.用最有效率的方法實現10×9的操作?
解析:10<<3+10
14.下面代碼中,請說出符合垃圾回收器(GC)的收集標準的行有哪些?
[java]view plaincopy

1.Objectaobj=newObject();
2.Objectbobj=newObject();
3.Objectcobj=newObject();
4.aobj=bobj;
5.aobj=cobj;
6.cobj=null;
7.aobj=null; 解析:第7行。注意,這類題型時可能遇到的最難題型了。
行1~3分別創建了Object類的3個對象:aobj、bobj和cobj。
行4:此時對象aobj的句柄指向bobj,所以該行的執行不能使aobj符合GC的收集標準。
行5:此時對象aobj的句柄指向cobj,所以該行的執行不能使aobj符合GC的收集標準。
行6:此時仍沒有任何一個對象符合GC的收集標準。
行7:對象cobj符合了GC的收集標準,因為cobj的句柄指向單一的地址空間。在第6行的時候,cobj已經被賦值為null,但是由于cobj同時還指向了aobj,所以此時cobj并不符合GC的收集標準。而在第7行,aobj所指向的地址空間已經被完全賦予了空值。所以,cobj最終符合了GC的收集標準。但對于aobj和bobj,仍然無法判斷其是否符合收集標準。
總之,在Java語言中,判斷一塊內存空間是否符合GC收集標準的標準之后以下兩個:
(1)給對象賦予了空值null,以后再沒有調用過。
(2)給對象賦予了新值,即重新分配了內存空間。
15.下列代碼有什么錯誤?
publicclassTest{
publicstaticvoidmain(String[]args){
Listlist=newArrayList();
list.add("Welcome");
list.add("to");
list.add("HUST");
for(Iteratori=list.iterator();i.hasNest();){
Strings=i.next();
System.out.println(s);
}
}
}
解析:本題會發生編譯錯誤。
這道題考察Java泛型的理解,在代碼中可以看到List泛型參數是String,也就是說,List只允許存放String類型的數據。該題的錯誤之處在于
for(Iterator i = list.iterator();i.hasNext();)
這一句上,通過API文檔可以看到Iterator迭代器也是需要采用泛型參數的。如果沒有加泛型參數,i.next();返回的結果是Object類型,所以
String s = i.next();
就會報類型不匹配的錯誤。為了類型安全,應該改為:
importjava.util.*;
publicclassTest{
publicstaticvoidmain(String[]args){
Listlist=newArrayList();
list.add("Welcome");
list.add("to");
list.add("HUST");
for(Iteratori=list.iterator();i.hasNest();){
Strings=i.next();
System.out.println(s);
}
}
}
16.進程進入等待狀態有哪幾種方式?
解析:本題屬于操作系統面試例題。
答案:進程進入等待狀態有3種方式:①CPU調度給優先級更高的thread,原先thread進入等待狀態。②阻塞的thread獲得資源或者信號,進入等待狀態。③時間片輪轉的情況下,如果時間片到了,也將進入等待狀態。
17.簡述synchronized和java.util.concurrent.locks.Lock的異同。
答案:主要相同點是,Lock能完成synchronized所實現的所有功能。主要不同點是,Lock有比synchronized更精確的線程語義和更好的性能。synchronized會自動釋放鎖,而Lock一定要求程序員手工釋放,并且必須在finally從句中釋放。
18.在JDBC連接數據庫編程應用開發中,利用哪個類可以實現連接數據庫?
A.Connection接口(√) B.PreparedStatement類
C.CallableStatement類 D.Statement類
解析:本題涉及以下知識點:JDBC數據庫連接問題。PreparedStatement類、CallableStatement類、Statement類這三個類的區別。三個選項中只有Connection接口可以用于連接數據庫。
19.請用三叉鏈表存儲二叉樹。
解析:三叉鏈表存儲的思想是讓每個節點不僅“記住”它的左、右兩個子節點,還要記住它的父節點,因此需要為每個節點增加left、right和parent三個指針,分別引用該節點的左、右兩個子節點和父節點。因此,三叉鏈表存儲的每個節點有如圖所示的結構。

代碼如下:
publicclassThreeLinkBinTree{
publicstaticclassTreeNode{
Objectdata;
TreeNodeleft;
TreeNoderight;
TreeNodeparent;
publicTreeNode(){}
publicTreeNode(Objectdata){
//Consructor...
}
publicTreeNode(Objectdata,TreeNodeleft,TreeNoderight,TreeNodeparent){
//Consructor...
}
}
privateTreeNoderoot;
//以默認的構造器來創建二叉樹
publicThreeLinkBinTree(){
this.root=newTreeNode;
}
//以指定根元素來創建二叉樹
publicThreeLinkBinTree(Edata){
this.root=newTreeNode(data);
}
/**
*為指定節點添加子節點
*@paramindex需要添加子節點的父節點的索引
*@paramdata新子節點的數據
*@paramisLeft是否為左節點
*@return新增的節點
*/
publicTreeNodeaddNode(TreeNodeparent,Edata,booleanisLeft){
//Method...
}
//判斷二叉樹是否為空
publicbooleanempty(){
//Method...
}
//返回根節點
publicTreeNoderoot(){
//Method...
}
//返回指定節點(非葉子)的左子結點,當左子結點不存在時返回null
publicEleftChild(TreeNodeparent){
//Method...
}
//返回指定節點(非葉子)的右子結點,當右子結點不存在時返回null
publicErightChild(TreeNodeparent){
//Method...
}
//返回該二叉樹的深度
publicintdeep(){
//Method...
}
//這是一個遞歸方法:每棵子樹的深度為其所有子樹的最大深度+1
privateintdeep(TreeNodenode){
//Method...
}
}
20.請寫出如下代碼的輸出結果。
[java]view plaincopy

classPerson{
Stringname;
intage;
publicPerson(Stringname,intage){
this.name=name;
this.age=age;
}
publicStringtoString(){
return"Person[name="+name+",age="+age+"]";
}
}
publicclassSoftReferenceTest{
publicstaticvoidmain(String[]args)throwsException{
SoftReference[]people=newSoftReference[10000];
for(inti=0;ipeople[i]=newSoftReference(
newPerson(
"名字"+i,(i+1)*4%100
)
);
}
System.out.println(people[2].get());
System.out.println(people[4].get());
System.gc();
System.runFinalization();
System.out.println(people[2].get());
System.out.println(people[4].get());
}
} 解析:主要考察Java內存回收機制中的引用的使用。在JVM內存管理中,有如下幾個概念,強引用,軟引用(SoftReference),弱引用(WeakReference)和虛引用(PhantomReference)。在本題中,使用軟引用是一個非常好的方案。當堆內存空間足夠時,垃圾回收機制不會回收Person對象,可以隨時重新訪問一個較好的方案。當堆內存空間不足時,系統也可以回收軟引用所引用的Person對象,從而提高程序運行性能,避免垃圾回收。
因此,當內存充足時,運行結果與強引用的功能類似:

修改上面程序的命令(為JVM指定使用較小的堆內存)如下:
java -Xmx2m -Xms2m SoftReferenceTest
運行上面的命令,可以看到如下結果:

使用java -Xmx2m -Xms2m SoftReferenceTest命令強制堆內存只有2m,而且程序創建一個長度為10000的數組,這樣將使系統內存緊張。在這種情況下,軟引用所引用的Java對象將會內垃圾回收,因此會出現這個結果。
21.以下代碼的運行結果是什么?
[java]view plaincopy

classBase{
inti;
Base(){
add(1);
System.out.println(i);
}
voidadd(intv){
i+=v;
System.out.println(i);
}
voidprint(){
System.out.println(i);
}
}
classMyBaseextendsBase{
MyBase(){
add(2);
}
voidadd(intv){
i+=v*2;
System.out.println(i);
}
}
publicclassTestClass{
publicstaticvoidmain(String[]args){
go(newMyBase());
//System.out.println();
}
staticvoidgo(Baseb){
b.add(8);
//b.print();
}
}
A.12 B.11 C.22(√) D.21
解析:程序流程是這樣的:在主函數中,首先執行new MyBase(),在這個過程中,子類會首先調用父類的構造函數;在父類的構造函數Base()中執行add()方法。在這里需要注意,這個add方法由于是在新建MyBase對象時調用的,將會首先查找MyBase類中是否有此方法。所以,Base()函數中的add(1)實際上是:
[java]view plaincopy

voidadd(intv){
i+=v*2;
System.out.println(i);
}
此時i的值即為2.在打印兩個2之后,父類的構造函數執行完畢,執行子類的構造函數,即MyBase(),這里的add(2)當然也是子類的。i的值就變為了6。
22. 下面哪些是Thread類的方法()
A start() B run() C exit() D getPriority()
答案:ABD
解析:exit()是System類的方法,如System.exit(0)。
23. 下面關于java.lang.Exception類的說法正確的是()
A 繼承自Throwable B Serialable CD 不記得,反正不正確
答案:A
解析:Java異常的基類為java.lang.Throwable,java.lang.Error和java.lang.Exception繼承 Throwable,RuntimeException和其它的Exception等繼承Exception,具體的RuntimeException繼承RuntimeException。java.lang.Exception: Throwable的子類,用于指示一種合理的程序想去catch的條件。即它僅僅是一種程序運行條件,而非嚴重錯誤,并且鼓勵用戶程序去catch它。checked exceptions:通常是從一個可以恢復的程序中拋出來的,并且最好能夠從這種異常中使用程序恢復。比如FileNotFoundException, ParseException等。檢查了的異常發生在編譯階段,必須要使用try…catch(或者throws)否則編譯不通過。unchecked exceptions:通常是如果一切正常的話本不該發生的異常,但是的確發生了。發生在運行期,具有不確定性,主要是由于程序的邏輯問題所引起的。比如ArrayIndexOutOfBoundException, ClassCastException等。從語言本身的角度講,程序不該去catch這類異常,雖然能夠從諸如RuntimeException這樣的異常中catch并恢復,但是并不鼓勵終端程序員這么做,因為完全沒要必要。因為這類錯誤本身就是bug,應該被修復,出現此類錯誤時程序就應該立即停止執行。 因此,面對Errors和unchecked exceptions應該讓程序自動終止執行,程序員不該做諸如try/catch這樣的事情,而是應該查明原因,修改代碼邏輯。
擴展:錯誤和異常的區別(Error vs Exception)
1)java.lang.Error: Throwable的子類,用于標記嚴重錯誤。合理的應用程序不應該去try/catch這種錯誤。絕大多數的錯誤都是非正常的,就根本不該出現的。
2) Error和RuntimeException 及其子類都是未檢查的異常(unchecked exceptions),而所有其他的Exception類都是檢查了的異常(checked exceptions).
RuntimeException:RuntimeException體系包括錯誤的類型轉換、數組越界訪問和試圖訪問空指針等等。
處理RuntimeException的原則是:如果出現 RuntimeException,那么一定是程序員的錯誤。例如,可以通過檢查數組下標和數組邊界來避免數組越界訪問異常。其他(IOException等等)checked異常一般是外部錯誤,例如試圖從文件尾后讀取數據等,這并不是程序本身的錯誤,而是在應用環境中出現的外部錯誤。
24. 下面程序的運行結果是()
[java]view plaincopy

Stringstr1="hello";
Stringstr2="he"+newString("llo");
System.err.println(str1==str2);
解析:System.err.println(str1 == str2);比較的是str1和str2在內存中的地址,而非值。
25.下列說法正確的有()
A. class中的constructor不可省略
B. constructor必須與class同名,但方法不能與class同名
C. constructor在一個對象被new時執行
D.一個class只能定義一個constructor
答案:C
解析:這里可能會有誤區,其實普通的類方法是可以和類名同名的,和構造方法唯一的區分就是,構造方法沒有返回值。
26. 具體選項不記得,但用到的知識如下:
String []a = new String[10];
則:a[0]~a[9] = null
a.length = 10
如果是int []a = new int[10];
則:a[0]~a[9] = 0
a.length = 10
27. 下面程序的運行結果:()
[java]view plaincopy

publicstaticvoidmain(Stringargs[]){
Threadt=newThread(){
publicvoidrun(){
pong();
}
};
t.run();
System.out.print("ping");
}
staticvoidpong(){
System.out.print("pong");
}
A pingpong B pongping C pingpong和pongping都有可能 D 都不輸出
答案:B
解析:去了static用類對象引用仍為B,對Thread的運行機制不是很了解,不知道為啥,歡迎大家補充。
28. 下列屬于關系型數據庫的是()
A.OracleBMySQLC IMS D MongoDB
答案:AB
解答:IMS(Information Management System)數據庫是IBM公司開發的兩種數據庫類型之一;
一種是關系數據庫,典型代表產品:DB2;
另一種則是層次數據庫,代表產品:IMS層次數據庫。
非關系型數據庫有MongoDB、memcachedb、Redis等。
29. GC線程是否為守護線程?()
答案:是
解析:線程分為守護線程和非守護線程(即用戶線程)。
只要當前JVM實例中尚存在任何一個非守護線程沒有結束,守護線程就全部工作;只有當最后一個非守護線程結束時,守護線程隨著JVM一同結束工作。
守護線程最典型的應用就是 GC (垃圾回收器)
30. volatile關鍵字是否能保證線程安全?()
答案:不能
解析:volatile關鍵字用在多線程同步中,可保證讀取的可見性,JVM只是保證從主內存加載到線程工作內存的值是最新的讀取值,而非cache中。但多個線程對
volatile的寫操作,無法保證線程安全。例如假如線程1,線程2 在進行read,load 操作中,發現主內存中count的值都是5,那么都會加載這個最新的值,在線程1堆count進行修改之后,會write到主內存中,主內存中的count變量就會變為6;線程2由于已經進行read,load操作,在進行運算之后,也會更新主內存count的變量值為6;導致兩個線程及時用volatile關鍵字修改之后,還是會存在并發的情況。
31. 下列說法正確的是()
A LinkedList繼承自List
B AbstractSet繼承自Set
C HashSet繼承自AbstractSet
D WeakMap繼承自HashMap
答案:AC
解析:下面是一張下載的Java中的集合類型的繼承關系圖,一目了然。

32. 存在使i + 1 < i的數嗎()
答案:存在
解析:如果i為int型,那么當i為int能表示的最大整數時,i+1就溢出變成負數了,此時不就
擴展:存在使i > j || i <= j不成立的數嗎()
答案:存在
解析:比如Double.NaN或Float.NaN。
33. 0.6332的數據類型是()
A float B double C Float D Double
答案:B
解析:默認為double型,如果為float型需要加上f顯示說明,即0.6332f
34. 下面哪個流類屬于面向字符的輸入流( )
ABufferedWriter BFileInputStream CObjectInputStream D InputStreamReader
答案:A
解析:Java的IO操作中有面向字節(Byte)和面向字符(Character)兩種方式。
面向字節的操作為以8位為單位對二進制的數據進行操作,對數據不進行轉換,這些類都是InputStream和OutputStream的子類。
面向字符的操作為以字符為單位對數據進行操作,在讀的時候將二進制數據轉為字符,在寫的時候將字符轉為二進制數據,這些類都是Reader和Writer的子類。
總結:
以InputStream(輸入)/OutputStream(輸出)為后綴的是字節流;
以Reader(輸入)/Writer(輸出)為后綴的是字符流。
擴展:Java流類圖結構,一目了然,解決大部分選擇題:

35. Java接口的修飾符可以為()
A private B protected C final D abstract
答案:CD
解析:接口很重要,為了說明情況,這里稍微啰嗦點:
(1)接口用于描述系統對外提供的所有服務,因此接口中的成員常量和方法都必須是公開(public)類型的,確保外部使用者能訪問它們;
(2)接口僅僅描述系統能做什么,但不指明如何去做,所以接口中的方法都是抽象(abstract)方法;
(3)接口不涉及和任何具體實例相關的細節,因此接口沒有構造方法,不能被實例化,沒有實例變量,只有靜態(static)變量;
(4)接口的中的變量是所有實現類共有的,既然共有,肯定是不變的東西,因為變化的東西也不能夠算共有。所以變量是不可變(final)類型,也就是常量了。
(5)接口中不可以定義變量?如果接口可以定義變量,但是接口中的方法又都是抽象的,在接口中無法通過行為來修改屬性。有的人會說了,沒有關系,可以通過 實現接口的對象的行為來修改接口中的屬性。這當然沒有問題,但是考慮這樣的情況。如果接口 A 中有一個public 訪問權限的靜態變量 a。按照 Java 的語義,我們可以不通過實現接口的對象來訪問變量 a,通過 A.a = xxx; 就可以改變接口中的變量 a 的值了。正如抽象類中是可以這樣做的,那么實現接口 A 的所有對象也都會自動擁有這一改變后的 a 的值了,也就是說一個地方改變了 a,所有這些對象中 a 的值也都跟著變了。這和抽象類有什么區別呢,怎么體現接口更高的抽象級別呢,怎么體現接口提供的統一的協議呢,那還要接口這種抽象來做什么呢?所以接口中 不能出現變量,如果有變量,就和接口提供的統一的抽象這種思想是抵觸的。所以接口中的屬性必然是常量,只能讀不能改,這樣才能為實現接口的對象提供一個統 一的屬性。
通俗的講,你認為是要變化的東西,就放在你自己的實現中,不能放在接口中去,接口只是對一類事物的屬性和行為更高層次的抽象。對修改關閉,對擴展(不同的實現 implements)開放,接口是對開閉原則的一種體現。
所以:
接口的方法默認是public abstract;
接口中不可以定義變量即只能定義常量(加上final修飾就會變成常量)。所以接口的屬性默認是public static final 常量,且必須賦初值。
注意:final和abstract不能同時出現。
36. 不通過構造函數也能創建對象嗎()
A 是 B 否
答案:A
解析:Java創建對象的幾種方式(重要):
(1) 用new語句創建對象,這是最常見的創建對象的方法。
(2) 運用反射手段,調用java.lang.Class或者java.lang.reflect.Constructor類的newInstance()實例方法。
(3) 調用對象的clone()方法。
(4) 運用反序列化手段,調用java.io.ObjectInputStream對象的 readObject()方法。
(1)和(2)都會明確的顯式的調用構造函數 ;(3)是在內存上對已有對象的影印,所以不會調用構造函數 ;(4)是從文件中還原類的對象,也不會調用構造函數。
37. ArrayList list = new ArrayList(20);中的list擴充幾次()
A 0 B 1 C 2 D 3
答案:A
解析:這里有點迷惑人,大家都知道默認ArrayList的長度是10個,所以如果你要往list里添加20個元素肯定要擴充一次(擴充為原來的1.5倍),但是這里顯示指明了需要多少空間,所以就一次性為你分配這么多空間,也就是不需要擴充了。
38. 下面哪些是對稱加密算法()
A DES B AES C DSA D RSA
答案:AB
解析:
常用的對稱加密算法有:DES、3DES、RC2、RC4、AES
常用的非對稱加密算法有:RSA、DSA、ECC
使用單向散列函數的加密算法:MD5、SHA
39.新建一個流對象,下面哪個選項的代碼是錯誤的?()
A)new BufferedWriter(new FileWriter("a.txt"));
B)new BufferedReader(new FileInputStream("a.dat"));
C)new GZIPOutputStream(new FileOutputStream("a.zip"));
D)new ObjectInputStream(new FileInputStream("a.dat"));
答案:B
解析:請記得13題的那個圖嗎?Reader只能用FileReader進行實例化。
40. 下面程序能正常運行嗎()
[java]view plaincopy

publicclassNULL{
publicstaticvoidhaha(){
System.out.println("haha");
}
publicstaticvoidmain(String[]args){
((NULL)null).haha();
}
}
答案:能正常運行
解析:輸出為haha,因為null值可以強制轉換為任何java類類型,(String)null也是合法的。但null強制轉換后是無效對象,其返回值還是為null,而static方法的調用是和類名綁定的,不借助對象進行訪問所以能正確輸出。反過來,沒有static修飾就只能用對象進行訪問,使用null調用對象肯定會報空指針錯了。這里和C++很類似。
41. 下面程序的運行結果是什么()
[java]view plaincopy

classHelloA{
publicHelloA(){
System.out.println("HelloA");
}
{System.out.println("I'mAclass");}
static{System.out.println("staticA");}
}
publicclassHelloBextendsHelloA{
publicHelloB(){
System.out.println("HelloB");
}
{System.out.println("I'mBclass");}
static{System.out.println("staticB");}
publicstaticvoidmain(String[]args){
newHelloB();
}
} 答案:
[plain]view plaincopy

staticA
staticB
I'mAclass
HelloA
I'mBclass
HelloB
解析:說實話我覺得這題很好,考查靜態語句塊、構造語句塊(就是只有大括號的那塊)以及構造函數的執行順序。
對象的初始化順序:(1)類加載之后,按從上到下(從父類到子類)執行被static修飾的語句;(2)當static語句執行完之后,再執行main方法;(3)如果有語句new了自身的對象,將從上到下執行構造代碼塊、構造器(兩者可以說綁定在一起)。
下面稍微修改下上面的代碼,以便更清晰的說明情況:
[java]view plaincopy

classHelloA{
publicHelloA(){
System.out.println("HelloA");
}
{System.out.println("I'mAclass");}
static{System.out.println("staticA");}
}
publicclassHelloBextendsHelloA{
publicHelloB(){
System.out.println("HelloB");
}
{System.out.println("I'mBclass");}
static{System.out.println("staticB");}
publicstaticvoidmain(String[]args){
System.out.println("-------mainstart-------");
newHelloB();
newHelloB();
System.out.println("-------mainend-------");
}
}
此時輸出結果為:
[plain]view plaincopy

staticA
staticB
-------mainstart-------
I'mAclass
HelloA
I'mBclass
HelloB
I'mAclass
HelloA
I'mBclass
HelloB
-------mainend------- 42.getCustomerInfo()方法如下,try中可以捕獲三種類型的異常,如果在該方法運行中產生了一個IOException,將會輸出什么結果:
[java]view plaincopy

publicvoidgetCustomerInfo(){
try{
//dosomethingthatmaycauseanException
}catch(java.io.FileNotFoundExceptionex){
System.out.print("FileNotFoundException!");
}catch(java.io.IOExceptionex){
System.out.print("IOException!");
}catch(java.lang.Exceptionex){
System.out.print("Exception!");
}
}
AIOException!
BIOException!Exception!
CFileNotFoundException!IOException!
DFileNotFoundException!IOException!Exception!
答案:A
解析:考察多個catch語句塊的執行順序。當用多個catch語句時,catch語句塊在次序上有先后之分。從最前面的catch語句塊依次先后進行異常類型匹配,這樣如果父異常在子異常類之前,那么首先匹配的將是父異常類,子異常類將不會獲得匹配的機會,也即子異常類型所在的catch語句塊將是不可到達的語句。所以,一般將父類異常類即Exception老大放在catch語句塊的最后一個。
43. 下面代碼的運行結果為:
[java]view plaincopy

importjava.io.*;
importjava.util.*;
publicclassfoo{
publicstaticvoidmain(String[]args){
Strings;
System.out.println("s="+s);
}
}
A代碼得到編譯,并輸出“s=”
B代碼得到編譯,并輸出“s=null”
C由于String s沒有初始化,代碼不能編譯通過
D代碼得到編譯,但捕獲到NullPointException異常
答案:C
解析:開始以為會輸出null什么的,運行后才發現Java中所有定義的基本類型或對象都必須初始化才能輸出值。
44. System.out.println("5" + 2);的輸出結果應該是()。
A52 B7 C2 D5
答案:A
解析:沒啥好說的,Java會自動將2轉換為字符串。
45.指出下列程序運行的結果()
[java]view plaincopy

publicclassExample{
Stringstr=newString("good");
char[]ch={'a','b','c'};
publicstaticvoidmain(Stringargs[]){
Exampleex=newExample();
ex.change(ex.str,ex.ch);
System.out.print(ex.str+"and");
System.out.print(ex.ch);
}
publicvoidchange(Stringstr,charch[]){
str="testok";
ch[0]='g';
}
}
A、good and abc
B、good and gbc
C、test ok and abc
D、test ok and gbc
答案:B
解析:大家可能以為Java中String和數組都是對象所以肯定是對象引用,然后就會選D,其實這是個很大的誤區:因為在java里沒有引用傳遞,只有值傳遞。這個值指的是實參的地址的拷貝,得到這個拷貝地址后,你可以通過它修改這個地址的內容(引用不變),因為此時這個內容的地址和原地址是同一地址,但是你不能改變這個地址本身使其重新引用其它的對象,也就是值傳遞,可能說的不是很清楚,下面給出一個完整的能說明情況的例子吧:
[java]view plaincopy

packagetest;
/**
*@descriptionJava中沒有引用傳遞只有值傳遞
*
*@authorAlexia
*@date2013-10-16
*
*/
classPerson{
privateStringname;
privateStringsex;
publicPerson(Stringx,Stringy){
this.name=x;
this.sex=y;
}
//重寫toString()方法,方便輸出
publicStringtoString(){
returnname+""+sex;
}
//交換對象引用
publicstaticvoidswapObject(Personp1,Personp2){
Persontmp=p1;
p1=p2;
p2=tmp;
}
//交換基本類型
publicstaticvoidswapInt(inta,intb){
inttmp=a;
a=b;
b=tmp;
}
//交換對象數組
publicstaticvoidswapObjectArray(Person[]p1,Person[]p2){
Person[]tmp=p1;
p1=p2;
p2=tmp;
}
//交換基本類型數組
publicstaticvoidswapIntArray(int[]x,int[]y){
int[]tmp=x;
x=y;
y=tmp;
}
//改變對象數組中的內容
publicstaticvoidchangeObjectArray(Person[]p1,Person[]p2){
Persontmp=p1[1];
p1[1]=p2[1];
p2[1]=tmp;
//再將p1[1]修改
Personp=newPerson("wjl","male");
p1[1]=p;
}
//改變基本類型數組中的內容
publicstaticvoidchangeIntArray(int[]x,int[]y){
inttmp=x[1];
x[1]=y[1];
y[1]=tmp;
x[1]=5;
}
}
publicclassByValueTest{
publicstaticvoidmain(String[]args){
//建立并構造兩個對象
Personp1=newPerson("Alexia","female");
Personp2=newPerson("Edward","male");
System.out.println("對象交換前:p1="+p1.toString());
System.out.println("對象交換前:p2="+p2.toString());
//交換p1對象和p2對象
Person.swapObject(p1,p2);
//從交換結果中看出,實際對象并未交換
System.out.println("\n對象交換后:p1="+p1.toString());
System.out.println("對象交換后:p2="+p2.toString());
//建立兩個對象數組
Person[]arraya=newPerson[2];
Person[]arrayb=newPerson[2];
//分別構造數組對象
arraya[0]=newPerson("Alexia","female");
arraya[1]=newPerson("Edward","male");
arrayb[0]=newPerson("jmwang","female");
arrayb[1]=newPerson("hwu","male");
System.out.println('\n'+"對象數組交換前:arraya[0]="
+arraya[0].toString()+",arraya[1]="
+arraya[1].toString());
System.out.println("對象數組交換前:arrayb[0]="
+arrayb[0].toString()+",arrayb[1]="
+arrayb[1].toString());
//交換這兩個對象數組
Person.swapObjectArray(arraya,arrayb);
System.out.println('\n'+"對象數組交換后:arraya[0]="
+arraya[0].toString()+",arraya[1]="
+arraya[1].toString());
System.out.println("對象數組交換后:arrayb[0]="
+arrayb[0].toString()+",arrayb[1]="
+arrayb[1].toString());
//建立兩個普通數組
int[]a=newint[2];
int[]b=newint[2];
//給數組個元素賦值
for(inti=0;ia[i]=i;
b[i]=i+1;
}
System.out.println('\n'+"基本類型數組交換前:a[0]="+a[0]+",a[1]="+a[1]);
System.out.println("基本類型數組交換前:b[0]="+b[0]+",b[1]="+b[1]);
//交換兩個基本類型數組
Person.swapIntArray(a,b);
System.out.println('\n'+"基本類型數組交換后:a[0]="+a[0]+",a[1]="+a[1]);
System.out.println("基本類型數組交換后:b[0]="+b[0]+",b[1]="+b[1]);
//改變對象數組的內容
Person.changeObjectArray(arraya,arrayb);
System.out.println('\n'+"對象數組內容交換并改變后:arraya[1]="+arraya[1].toString());
System.out.println("對象數組內容交換并改變后:arrayb[1]="+arrayb[1].toString());
//改變基本類型數組的內容
Person.changeIntArray(a,b);
System.out.println('\n'+"基本類型數組內容交換并改變后:a[1]="+a[1]);
System.out.println("基本類型數組內容交換并改變后:b[1]="+b[1]);
}
} 程序有些啰嗦,但能反映問題,該程序運行結果為:
[plain]view plaincopy

對象交換前:p1=Alexiafemale
對象交換前:p2=Edwardmale
對象交換后:p1=Alexiafemale
對象交換后:p2=Edwardmale
對象數組交換前:arraya[0]=Alexiafemale,arraya[1]=Edwardmale
對象數組交換前:arrayb[0]=jmwangfemale,arrayb[1]=hwumale
對象數組交換后:arraya[0]=Alexiafemale,arraya[1]=Edwardmale
對象數組交換后:arrayb[0]=jmwangfemale,arrayb[1]=hwumale
基本類型數組交換前:a[0]=0,a[1]=1
基本類型數組交換前:b[0]=1,b[1]=2
基本類型數組交換后:a[0]=0,a[1]=1
基本類型數組交換后:b[0]=1,b[1]=2
對象數組內容交換并改變后:arraya[1]=wjlmale
對象數組內容交換并改變后:arrayb[1]=Edwardmale
基本類型數組內容交換并改變后:a[1]=5
基本類型數組內容交換并改變后:b[1]=1 說明:不管是對象、基本類型還是對象數組、基本類型數組,在函數中都不能改變其實際地址但能改變其中的內容。
46.要從文件"file.dat"中讀出第10個字節到變量c中,下列哪個方法適合?()
AFileInputStream in=new FileInputStream("file.dat"); in.skip(9); int c=in.read();
BFileInputStream in=new FileInputStream("file.dat"); in.skip(10); int c=in.read();
CFileInputStream in=new FileInputStream("file.dat"); int c=in.read();
DRandomAccessFile in=new RandomAccessFile("file.dat"); in.skip(9); int c=in.readByte();
答案:A、D
解析:long skip(long n)作用是跳過n個字節不讀,主要用在包裝流中的,因為一般流(如FileInputStream)只能順序一個一個的讀不能跳躍讀,但是包裝流可以用skip方法跳躍讀取。那么什么是包裝流呢?各種字節節點流類,它們都只具有讀寫字節內容的方法,以FileInputStream與FileOutputStream為例,它們只能在文件中讀取或者向文件中寫入字節,在實際應用中我們往往需要在文件中讀取或者寫入各種類型的數據,就必須先將其他類型的數據轉換成字節數組后寫入文件,或者從文件中讀取到的字節數組轉換成其他數據類型,想想都很麻煩!!因此想通過FileOutputStream將一個浮點小數寫入到文件中或將一個整數寫入到文件時是非常困難的。這時就需要包裝類DataInputStream/DataOutputStream,它提供了往各種輸入輸出流對象中讀入或寫入各種類型的數據的方法。
DataInputStream/DataOutputStream并沒有對應到任何具體的流設備,一定要給它傳遞一個對應具體流設備的輸入或輸出流對象,完成類似DataInputStream/DataOutputStream功能的類就是一個包裝類,也叫過濾流類或處理流類。它對InputOutStream/OutputStream流類進行了包裝,使編程人員使用起來更方便。其中DataInputStream包裝類的構造函數語法:public DataInputStream(InputStream in)。包裝類也可以包裝另外一個包裝類。
首先BC肯定 是錯的,那A正確嗎?按上面的解析應該也不對,但我試了下,發現A也是正確的,與網上解析的資料有些出入,下面是我的code:
[java]view plaincopy

importjava.io.FileInputStream;
importjava.io.FileOutputStream;
importjava.io.IOException;
publicclassFileStreamTest{
publicstaticvoidmain(String[]args)throwsIOException{
//TODOAuto-generatedmethodstub
FileOutputStreamout=newFileOutputStream("file.dat");
byte[]b={1,2,3,4,5,6,7,8,9,10};
out.write(b);
out.close();
FileInputStreamin=newFileInputStream("file.dat");
in.skip(9);//跳過前面的9個字節
intc=in.read();
System.out.println(c);//輸出為10
in.close();
}
} 那么D呢,RandomAccessFile是IO包的類,但是其自成一派,從Object直接繼承而來。可以對文件進行讀取和寫入。支持文件的隨機訪問,即可以隨機讀取文件中的某個位置內容,這么說RandomAccessFile肯定可以達到題目的要求,但是選項有些錯誤,比如RandomAccessFile的初始化是兩個參數而非一個參數,采用的跳躍讀取方法是skipBytes()而非skip(),即正確的寫法是:
[java]view plaincopy

RandomAccessFilein=newRandomAccessFile("file.dat","r");
in.skipBytes(9);
intc=in.readByte(); 這樣也能讀到第十個字節,也就是A和D都能讀到第十個字節。
47. 下面的方法,當輸入為2的時候返回值是多少?()
[java]view plaincopy

publicstaticintgetValue(inti){
intresult=0;
switch(i){
case1:
result=result+i;
case2:
result=result+i*2;
case3:
result=result+i*3;
}
returnresult;
}
A0 B2 C4 D10
答案:D
解析:注意這里case后面沒有加break,所以從case 2開始一直往下運行。
48.選項中哪一行代碼可以替換題目中//add code here而不產生編譯錯誤?()
[java]view plaincopy

publicabstractclassMyClass{
publicintconstInt=5;
//addcodehere
publicvoidmethod(){
}
}
Apublic abstract void method(int a);
B constInt = constInt + 5;
Cpublic int method();
Dpublic abstract void anotherMethod() {}
答案:A
解析:考察抽象類的使用。
抽象類遵循的原則:
(1)abstract關鍵字只能修飾類和方法,不能修飾字段。
(2)抽象類不能被實例化(無法使用new關鍵字創建對象實例),只能被繼承。
(3)抽象類可以包含屬性,方法,構造方法,初始化塊,內部類,枚舉類,和普通類一樣,普通方法一定要實現,變量可以初始化或不初始化但不能初始化后在抽象類中重新賦值或操作該變量(只能在子類中改變該變量)。
(4)抽象類中的抽象方法(加了abstract關鍵字的方法)不能實現。
(5)含有抽象方法的類必須定義成抽象類。
擴展:抽象類和接口的區別,做個總結吧:
(1)接口是公開的,里面不能有私有的方法或變量,是用于讓別人使用的,而抽象類是可以有私有方法或私有變量的。
(2)abstract class 在 Java 語言中表示的是一種繼承關系,一個類只能使用一次繼承關系。但是,一個類卻可以實現多個interface,實現多重繼承。接口還有標識(里面沒有任何方法,如Remote接口)和數據共享(里面的變量全是常量)的作用。
(3)在abstract class 中可以有自己的數據成員,也可以有非abstarct的成員方法,而在interface中,只能夠有靜態的不能被修改的數據成員(也就是必須是 static final的,不過在 interface中一般不定義數據成員),所有的成員方法默認都是 public abstract 類型的。
(4)abstract class和interface所反映出的設計理念不同。其實abstract class表示的是"is-a"關系,interface表示的是"has-a"關系。
(5)實現接口的一定要實現接口里定義的所有方法,而實現抽象類可以有選擇地重寫需要用到的方法,一般的應用里,最頂級的是接口,然后是抽象類實現接口,最后才到具體類實現。抽象類中可以有非抽象方法。接口中則不能有實現方法。
(6)接口中定義的變量默認是public static final 型,且必須給其初值,所以實現類中不能重新定義,也不能改變其值。抽象類中的變量默認是 friendly 型,其值可以在子類中重新定義,也可以在子類中重新賦值。
49. 閱讀Shape和Circle兩個類的定義。在序列化一個Circle的對象circle到文件時,下面哪個字段會被保存到文件中?( )
[java]view plaincopy

classShape{
publicStringname;
}
classCircleextendsShapeimplementsSerializable{
privatefloatradius;
transientintcolor;
publicstaticStringtype="Circle";
}
Aname
Bradius
Ccolor
Dtype
答案:B
解析:Javatransient詳解
(1). transient的作用及使用方法
我們都知道一個對象只要實現了Serilizable接口,這個對象就可以被序列化,java的這種序列化模式為開發者提供了很多便利,我們可以不必關系具體序列化的過程,只要這個類實現了Serilizable接口,這個類的所有屬性和方法都會自動序列化。
然而在實際開發過程中,我們常常會遇到這樣的問題,這個類的有些屬性需要序列化,而其他屬性不需要被序列化,打個比方,如果一個用戶有一些敏感信息(如密碼,銀行卡號等),為了安全起見,不希望在網絡操作(主要涉及到序列化操作,本地序列化緩存也適用)中被傳輸,這些信息對應的變量就可以加上transient關鍵字。換句話說,這個字段的生命周期僅存于調用者的內存中而不會寫到磁盤里持久化。
總之,java 的transient關鍵字為我們提供了便利,你只需要實現Serilizable接口,將不需要序列化的屬性前添加關鍵字transient,序列化對象的時候,這個屬性就不會序列化到指定的目的地中。
[java]view plaincopy

importjava.io.FileInputStream;
importjava.io.FileNotFoundException;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.io.ObjectInputStream;
importjava.io.ObjectOutputStream;
importjava.io.Serializable;
/**
*@description使用transient關鍵字不序列化某個變量
*注意讀取的時候,讀取數據的順序一定要和存放數據的順序保持一致
*
*@authorAlexia
*@date2013-10-15
*/
publicclassTransientTest{
publicstaticvoidmain(String[]args){
Useruser=newUser();
user.setUsername("Alexia");
user.setPasswd("123456");
System.out.println("readbeforeSerializable:");
System.out.println("username:"+user.getUsername());
System.err.println("password:"+user.getPasswd());
try{
ObjectOutputStreamos=newObjectOutputStream(
newFileOutputStream("C:/user.txt"));
os.writeObject(user);//將User對象寫進文件
os.flush();
os.close();
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}
try{
ObjectInputStreamis=newObjectInputStream(newFileInputStream(
"C:/user.txt"));
user=(User)is.readObject();//從流中讀取User的數據
is.close();
System.out.println("\nreadafterSerializable:");
System.out.println("username:"+user.getUsername());
System.err.println("password:"+user.getPasswd());
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
}
}
classUserimplementsSerializable{
privatestaticfinallongserialVersionUID=8294180014912103005L;
privateStringusername;
privatetransientStringpasswd;
publicStringgetUsername(){
returnusername;
}
publicvoidsetUsername(Stringusername){
this.username=username;
}
publicStringgetPasswd(){
returnpasswd;
}
publicvoidsetPasswd(Stringpasswd){
this.passwd=passwd;
}
} 輸出為:
[java]view plaincopy

readbeforeSerializable:
username:Alexia
password:123456
readafterSerializable:
username:Alexia
password:null 密碼字段為null,說明反序列化時根本沒有從文件中獲取到信息。
(2). transient使用小結
1)一旦變量被transient修飾,變量將不再是對象持久化的一部分,該變量內容在序列化后無法獲得訪問。
2)transient關鍵字只能修飾變量,而不能修飾方法和類。注意,本地變量是不能被transient關鍵字修飾的。變量如果是用戶自定義類變量,則該類需要實現Serializable接口。
3)被transient關鍵字修飾的變量不再能被序列化,一個靜態變量不管是否被transient修飾,均不能被序列化。
第三點可能有些人很迷惑,因為發現在User類中的username字段前加上transient關鍵字后,程序運行結果依然不變,即static類型的username也讀出來為“Alexia”了,這不與第三點說的矛盾嗎?實際上是這樣的:第三點確實沒錯(一個靜態變量不管是否被transient修飾,均不能被序列化),反序列化后類中static型變量username的值為當前JVM中對應static變量的值,這個值是JVM中的不是反序列化得出的,不相信?好吧,下面我來證明:
[java]view plaincopy

importjava.io.FileInputStream;
importjava.io.FileNotFoundException;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.io.ObjectInputStream;
importjava.io.ObjectOutputStream;
importjava.io.Serializable;
/**
*@description使用transient關鍵字不序列化某個變量
*注意讀取的時候,讀取數據的順序一定要和存放數據的順序保持一致
*
*@authorAlexia
*@date2013-10-15
*/
publicclassTransientTest{
publicstaticvoidmain(String[]args){
Useruser=newUser();
user.setUsername("Alexia");
user.setPasswd("123456");
System.out.println("readbeforeSerializable:");
System.out.println("username:"+user.getUsername());
System.err.println("password:"+user.getPasswd());
try{
ObjectOutputStreamos=newObjectOutputStream(
newFileOutputStream("C:/user.txt"));
os.writeObject(user);//將User對象寫進文件
os.flush();
os.close();
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}
try{
//在反序列化之前改變username的值
User.username="jmwang";
ObjectInputStreamis=newObjectInputStream(newFileInputStream(
"C:/user.txt"));
user=(User)is.readObject();//從流中讀取User的數據
is.close();
System.out.println("\nreadafterSerializable:");
System.out.println("username:"+user.getUsername());
System.err.println("password:"+user.getPasswd());
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}catch(ClassNotFoundExceptione){
e.printStackTrace();
}
}
}
classUserimplementsSerializable{
privatestaticfinallongserialVersionUID=8294180014912103005L;
publicstaticStringusername;
privatetransientStringpasswd;
publicStringgetUsername(){
returnusername;
}
publicvoidsetUsername(Stringusername){
this.username=username;
}
publicStringgetPasswd(){
returnpasswd;
}
publicvoidsetPasswd(Stringpasswd){
this.passwd=passwd;
}
} 輸出為:
[java]view plaincopy

readbeforeSerializable:
username:Alexia
password:123456
readafterSerializable:
username:jmwang
password:null 這說明反序列化后類中static型變量username的值為當前JVM中對應static變量的值,為修改后jmwang,而不是序列化時的值Alexia。
(3). transient使用細節——被transient關鍵字修飾的變量真的不能被序列化嗎?
思考下面的例子:
[java]view plaincopy

importjava.io.Externalizable;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.io.ObjectInput;
importjava.io.ObjectInputStream;
importjava.io.ObjectOutput;
importjava.io.ObjectOutputStream;
/**
*@descripitonExternalizable接口的使用
*
*@authorAlexia
*@date2013-10-15
*
*/
publicclassExternalizableTestimplementsExternalizable{
privatetransientStringcontent="是的,我將會被序列化,不管我是否被transient關鍵字修飾";
@Override
publicvoidwriteExternal(ObjectOutputout)throwsIOException{
out.writeObject(content);
}
@Override
publicvoidreadExternal(ObjectInputin)throwsIOException,
ClassNotFoundException{
content=(String)in.readObject();
}
publicstaticvoidmain(String[]args)throwsException{
ExternalizableTestet=newExternalizableTest();
ObjectOutputout=newObjectOutputStream(newFileOutputStream(
newFile("test")));
out.writeObject(et);
ObjectInputin=newObjectInputStream(newFileInputStream(newFile(
"test")));
et=(ExternalizableTest)in.readObject();
System.out.println(et.content);
out.close();
in.close();
}
} content變量會被序列化嗎?好吧,我把答案都輸出來了,是的,運行結果就是:
[java]view plaincopy

是的,我將會被序列化,不管我是否被transient關鍵字修飾
這是為什么呢,不是說類的變量被transient關鍵字修飾以后將不能序列化了嗎?
我們知道在Java中,對象的序列化可以通過實現兩種接口來實現,若實現的是Serializable接口,則所有的序列化將會自動進行,若實現的是Externalizable接口,則沒有任何東西可以自動序列化,需要在writeExternal方法中進行手工指定所要序列化的變量,這與是否被transient修飾無關。因此第二個例子輸出的是變量content初始化的內容,而不是null。
50.下面是People和Child類的定義和構造方法,每個構造方法都輸出編號。在執行new Child("mike")的時候都有哪些構造方法被順序調用?請選擇輸出結果( )
[java]view plaincopy

classPeople{
Stringname;
publicPeople(){
System.out.print(1);
}
publicPeople(Stringname){
System.out.print(2);
this.name=name;
}
}
classChildextendsPeople{
Peoplefather;
publicChild(Stringname){
System.out.print(3);
this.name=name;
father=newPeople(name+":F");
}
publicChild(){
System.out.print(4);
}
}
A312 B 32 C 432 D 132
答案:D
解析:考察的又是父類與子類的構造函數調用次序。在Java中,子類的構造過程中必須調用其父類的構造函數,是因為有繼承關系存在時,子類要把父類的內容繼承下來。但如果父類有多個構造函數時,該如何選擇調用呢?
第一個規則:子類的構造過程中,必須調用其父類的構造方法。一個類,如果我們不寫構造方法,那么編譯器會幫我們加上一個默認的構造方法(就是沒有參數的構造方法),但是如果你自己寫了構造方法,那么編譯器就不會給你添加了,所以有時候當你new一個子類對象的時候,肯定調用了子類的構造方法,但是如果在子類構造方法中我們并沒有顯示的調用基類的構造方法,如:super();這樣就會調用父類沒有參數的構造方法。
第二個規則:如果子類的構造方法中既沒有顯示的調用基類構造方法,而基類中又沒有無參的構造方法,則編譯出錯,所以,通常我們需要顯示的:super(參數列表),來調用父類有參數的構造函數,此時無參的構造函數就不會被調用。
總之,一句話:子類沒有顯示調用父類構造函數,不管子類構造函數是否帶參數都默認調用父類無參的構造函數,若父類沒有則編譯出錯。
最后,給大家出個思考題:下面程序的運行結果是什么?
[java]view plaincopy

publicclassDerviedextendsBase{
privateStringname="dervied";
publicDervied(){
tellName();
printName();
}
publicvoidtellName(){
System.out.println("Derviedtellname:"+name);
}
publicvoidprintName(){
System.out.println("Derviedprintname:"+name);
}
publicstaticvoidmain(String[]args){
newDervied();
}
}
classBase{
privateStringname="base";
publicBase(){
tellName();
printName();
}
publicvoidtellName(){
System.out.println("Basetellname:"+name);
}
publicvoidprintName(){
System.out.println("Baseprintname:"+name);
}
}
運行結果為:
Dervied tell name: null
Dervied print name: null
Dervied tell name: dervied
Dervied print name: dervied
就愛閱讀www.92to.com網友整理上傳,為您提供最全的知識大全,期待您的分享,轉載請注明出處。
歡迎轉載:http://www.kanwencang.com/bangong/20161206/63490.html
文章列表