国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

JavaSE面試題集錦

2019-11-06 08:39:18
字體:
來源:轉載
供稿:網友
一、IO流1.文件切割器public class SplitFileDemo {PRivate static final int SIZE = 1024 * 1024;/*** @param args* @throws Exception*/public static void main(String[] args) throws Exception {File file = new File("c://aa.mp3");splitFile_2(file);}private static void splitFile_2(File file) throws IOException {// 用讀取流關聯源文件。FileInputStream fis = new FileInputStream(file);// 定義一個1M的緩沖區。byte[] buf = new byte[SIZE];// 創建目的。245FileOutputStream fos = null;int len = 0;int count = 1;/** 切割文件時,必須記錄住被切割文件的名稱,以及切割出來碎片文件的個數。 以方便于合并。* 這個信息為了進行描述,使用鍵值對的方式。用到了properties對象**/Properties prop = new Properties();File dir = new File("c://partfiles");if (!dir.exists())dir.mkdirs();while ((len = fis.read(buf)) != -1) {fos = new FileOutputStream(new File(dir, (count++) + ".part"));fos.write(buf, 0, len);fos.close();}// 將被切割文件的信息保存到prop集合中。prop.setProperty("partcount", count + "");prop.setProperty("filename", file.getName());fos = new FileOutputStream(new File(dir, count + ".properties"));// 將prop集合中的數據存儲到文件中。prop.store(fos, "save file info");fos.close();fis.close();}public static void splitFile(File file) throws IOException {// 用讀取流關聯源文件。FileInputStream fis = new FileInputStream(file);// 定義一個1M的緩沖區。byte[] buf = new byte[SIZE];// 創建目的。FileOutputStream fos = null;int len = 0;int count = 1;File dir = new File("c://partfiles");if (!dir.exists())dir.mkdirs();while ((len = fis.read(buf)) != -1) {fos = new FileOutputStream(new File(dir, (count++) + ".part"));fos.write(buf, 0, len);}fos.close();fis.close();}}2. 定義功能,獲取一個應用程序運行的次數,如果超過5次,給出使用次數已到請注冊的提示。并不要在運行程序。public class PropertiesTest {/*** @param args* @throws IOException* @throws Exception*/public static void main(String[] args) throws IOException {getAppCount();}public static void getAppCount() throws IOException {// 將配置文件封裝成File對象。File confile = new File("count.properties");if (!confile.exists()) {confile.createNewFile();}FileInputStream fis = new FileInputStream(confile);Properties prop = new Properties();prop.load(fis);// 從集合中通過鍵獲取次數。String value = prop.getProperty("time");// 定義計數器。記錄獲取到的次數。int count = 0;if (value != null) {count = Integer.parseInt(value);if (count >= 5) {// System.out.println("使用次數已到,請注冊,給錢! ");// return;throw new RuntimeException("使用次數已到,請注冊,給錢! ");}}count++;// 將改變后的次數重新存儲到集合中。prop.setProperty("time", count + "");FileOutputStream fos = new FileOutputStream(confile);prop.store(fos, "");fos.close();fis.close();}}3. 對指定目錄進行所有內容的列出(包含子目錄中的內容)public class FileTest {/*** @param args*/public static void main(String[] args) {File dir = new File("e://demodir");listAll(dir, 0);}public static void listAll(File dir, int level) {System.out.println(getSpace(level) + dir.getName());二、多線程1. java 多線程同步的五種方法http://www.codeceo.com/article/java-multi-thread-sync.html2. 什么是ThreadLocal變量?https://my.oschina.net/lichhao/blog/1113623. 一個線程運行時發生異常會怎樣?這是我在一次面試中遇到的一個很刁鉆的Java面試題, 簡單的說,如果異常沒有被捕獲該線程將會停止執行。Thread.UncaughtExceptionHandler是用于處理未捕獲異常造成線程突然中斷情況的一個內嵌接口。當一個未捕獲異常將造成線程中斷的時候JVM會使用Thread.getUncaughtExceptionHandler()來查詢線程的UncaughtExceptionHandler并將線程和異常作為參數傳遞給handler的uncaughtException()方法進行處理。4. sleep() 和 wait() 有什么區別?sleep就是正在執行的線程主動讓出cpu,cpu去執行其他線程,在sleep指定的時間過后,cpu才會回到這個線程上繼續往下執行,如果當前線程進入了同步鎖,sleep方法并不會釋放鎖,即使當前線程使用sleep方法讓出了cpu,但其他被同步鎖擋住了的線程也無法得到執行。wait是指在一個已經進入了同步鎖的線程內,讓自己暫時讓出同步鎖,以便其他正在等待此鎖的線程可以得到同步鎖并運行,只有其他線程調用了notify方法(notify并不釋放鎖,只是告訴調用過wait方法的線程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在別人手里,別人還沒釋放。如果notify方法后面的代碼還有很多,需要這些代碼執行完后才會釋放鎖,可以在notfiy方法后增加一個等待和一些代碼,看看效果),調用wait方法的線程就會解除wait狀態和程序可以再次得到鎖后繼續向下運行。對于wait的講解一定要配合例子代碼來說明,才顯得自己真明白。5. 請闡述一下你對JAVA多線程中“鎖”的概念的理解。6. 簡述synchronized和java.util.concurrent.locks.Lock的異同 ?主要相同點:Lock能完成synchronized所實現的所有功能主要不同點:Lock有比synchronized更精確的線程語義和更好的性能。synchronized會自動釋放鎖,而Lock一定要求程序員手工釋放,并且必須在finally從句中釋放。7. 線程的基本概念、線程的基本狀態以及狀態之間的關系線程是進程中某個單一順序的控制流,是程序執行流的最小單位。線程由線程ID、當前指令指針、寄存器集合和堆棧組成。線程是進程的一個實體,是被系統調度和分配的基本單位,線程與同一進程中的其他線程共享進程的全部資源。      線程有五種基本狀態:新生狀態,就緒狀態,運行狀態,阻塞狀態,死亡狀態。狀態間關系如下圖:  http://www.cnblogs.com/Rosanna/p/3581835.html8. 當一個線程進入一個對象的一個synchronized方法后,其它線程是否可進入此對象的其它方法?分幾種情況:    1.其他方法前是否加了synchronized關鍵字,如果沒加,則能。    2.如果這個方法內部調用了wait,則可以進入其他synchronized方法。    3.如果其他個方法都加了synchronized關鍵字,并且內部沒有調用wait,則不能。    4.如果其他方法是static,它用的同步鎖是當前類的字節碼,與非靜態的方法不能同步,因為非靜態的方法用的是this。 來源: http://blog.csdn.net/nyistzp/article/details/141275479. 同步和異步有何異同,在什么情況下分別使用他們?舉例說明。同步和異步是相對于多線程來說的。        同步可防止并發, 主要出于數據安全的考慮。如果數據將在線程間共享,例如正在寫的數據以后可能被另一個線程讀到,或者正在讀的數據可能已經被另一個線程寫過了,那么這些數據就是共享數據,必須進行同步存取。        異步允許并發,當應用程序在對象上調用了一個需要花費很長時間來執行的方法,并且不希望讓程序等待方法的返回時,就應該使用異步編程,在很多情況下采用異步途徑往往更有效率。來源: http://blog.csdn.net/yuguiyang1990/article/details/1533982710. java中有幾種方法可以實現一個線程?用什么關鍵字修飾同步方法? stop()和suspend()方法為何不推薦使用?第一種:步驟:1,定義一個類繼承Thread類。2,覆蓋Thread類中的run方法。3,直接創建Thread的子類對象創建線程。4,調用start方法開啟線程并調用線程的任務run方法執行。  new Thread(){}.start();這表示調用Thread子類對象的run方法,new Thread(){}表示一個Thread的匿名子類的實例對象,子類加上run方法后的代碼如下:new Thread(){    public void run(){    }}.start();第二種:1,定義類實現Runnable接口。2,覆蓋接口中的run方法,將線程的任務代碼封裝到run方法中。3,通過Thread類創建線程對象,并將Runnable接口的子類對象作為Thread類的構造函數的參數進行傳遞。為什么?因為線程的任務都封裝在Runnable接口子類對象的run方法中。所以要在線程對象創建時就必須明確要運行的任務。4,調用線程對象的start方法開啟線程。  new Thread(new Runnable(){}).start();這表示調用Thread對象接受的Runnable對象的run方法,new Runnable(){}表示一個Runnable的匿名子類的實例對象,runnable的子類加上run方法后的代碼如下:new Thread(new Runnable(){    public void run(){    }}).start();從java5開始,還有如下一些線程池創建多線程的方式:ExecutorService pool = Executors.newFixedThreadPool(3)for(int i=0;i<10;i++){pool.execute(new Runable(){public void run(){}});}Executors.newCachedThreadPool().execute(new Runable(){public void run(){}});Executors.newSingleThreadExecutor().execute(new Runable(){public void run(){}});有兩種實現方法,分別使用new Thread()和new Thread(runnable)形式,第一種直接調用thread的run方法,所以,我們往往使用Thread子類,即new SubThread()。第二種調用runnable的run方法。有兩種實現方法,分別是繼承Thread類與實現Runnable接口用synchronized關鍵字修飾同步方法反對使用stop(),是因為它不安全。它會解除由線程獲取的所有鎖定,而且如果對象處于一種不連貫狀態,那么其他線程能在那種狀態下檢查和修改它們。結果很難檢查出真正的問題所在。suspend()方法容易發生死鎖。調用suspend()的時候,目標線程會停下來,但卻仍然持有在這之前獲得的鎖定。此時,其他任何線程都不能訪問鎖定的資源,除非被"掛起"的線程恢復運行。對任何線程來說,如果它們想恢復目標線程,同時又試圖使用任何一個鎖定的資源,就會造成死鎖。所以不應該使用suspend(),而應在自己的Thread類中置入一個標志,指出線程應該活動還是掛起。若標志指出線程應該掛起,便用wait()命其進入等待狀態。若標志指出線程應當恢復,則用一個notify()重新啟動線程。三、基礎語法1. 給出下面的二叉樹先序、中序、后序遍歷的序列? 先序:    A    B    D    E    G    I    H    C    F 中序:    D    B    G    I    E    H    A    C    F后序:    D    I    G    H    E    B    F    C    A2. 為什么在重寫了equals()方法之后也必須重寫hashCode()方法?object對象中的 public boolean equals(Object obj),對于任何非空引用值 x 和 y,當且僅當 x 和 y 引用同一個對象時,此方法才返回 true;注意:當此方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCode 方法的常規協定,該協定聲明相等對象必須具有相等的哈希碼。如下:(1)當obj1.equals(obj2)為true時,obj1.hashCode() == obj2.hashCode()必須為true (2)當obj1.hashCode() == obj2.hashCode()為false時,obj1.equals(obj2)必須為false如果不重寫equals,那么比較的將是對象的引用是否指向同一塊內存地址,重寫之后目的是為了比較兩個對象的value值是否相等。特別指出利用equals比較八大包裝對象(如int,float等)和String類(因為該類已重寫了equals和hashcode方法)對象時,默認比較的是值,在比較其它自定義對象時都是比較的引用地址hashcode是用于散列數據的快速存取,如利用HashSet/HashMap/Hashtable類來存儲數據時,都是根據存儲對象的hashcode值來進行判斷是否相同的。這樣如果我們對一個對象重寫了euqals,意思是只要對象的成員變量值都相等那么euqals就等于true,但不重寫hashcode,那么我們再new一個新的對象,當原對象.equals(新對象)等于true時,兩者的hashcode卻是不一樣的,由此將產生了理解的不一致,如在存儲散列集合時(如Set類),將會存儲了兩個值一樣的對象,導致混淆,因此,就也需要重寫hashcode()來源: http://www.cnblogs.com/happyPawpaw/p/3744971.html3. abstract的method是否可同時是static,是否可同時是native,是否可同時是synchronized?1、abstract與static(what)abstract:用來聲明抽象方法,抽象方法沒有方法體,不能被直接調用,必須在子類overriding后才能使用static:用來聲明靜態方法,靜態方法可以被類及其對象調用(how)static與abstract不能同時使用(why)用static聲明方法表明這個方法在不生成類的實例時可直接被類調用,而abstract方法不能被調用,兩者矛盾。2、abstract與native(what)native:用來聲明本地方法,該方法的實現由非java 語言實現,比如C。一般用于java與外環境交互,或與操作系統交互(how)native 可以與所有其它的java 標識符連用,但是abstract除外。(why)因為native 暗示這些方法是有實現體的,只不過這些實現體是非java 的,但是abstract卻顯然的指明這些方法無實現體。3、abstract與synchronized(what)synchronized:用于防止多個線程同時調用一個對象的該方法,與static連用可防止多個線程同時調用一個類的該方法(how)abstract與synchronized不能同時使用(why)從synchronized的功能也可以看出,用synchronized的前提是該方法可以被直接調用,顯然和abstract連用來源: http://zhoujiyu.blog.51cto.com/675686/4289994. 能不能自己寫個類,也叫java.lang.String?http://blog.csdn.net/tang9140/article/details/427384335. heap和stack有什么區別。棧內存:在函數中定義的一些基本類型的變量和對象的引用變量都在函數的棧內存中分配。 棧內存主要存放的是基本類型類型的數據 如、( int, short, long, byte, float, double, boolean, char) 和對象句柄。并沒有有String基本類型、在棧內存的數據的大小及生存周期是必須確定的、其優點是寄存速度快、、棧數據可以共享、缺點是數據固定、不夠靈活。棧的共享:1. String a = "abc";2. String b = "abc";3. System.out.println(a==b);結果為true 這就說明了a b其實指向同一個值注意,我們這里并不用a.equals(b);的方式,因為這將比較兩個字符串的值是否相等。==號,根據JDK的說明,只有在兩個引用都指向了同一個對象時才返回真值。而我們在這里要看的是,a與b是否都指向了同一個對象。結果說明,JVM創建了兩個引用a和b,但只創建了一個對象,而且兩個引用都指向了這個對象。首先它會在棧中創建一個變量為a的引用,然后查找棧中是否有abc這個值,如果沒找到,就將abc存放進來,然后將a指向abc。接著處理String b = "abc";在創建完b的引用變量后,因為在棧中已經有abc這個值,便將b直接指向abc。這樣,就出現了a與b同時指向abc特別注意的是,這種字面值的引用與類對象的引用不同。假定兩個類對象的引用同時指向一個對象,如果一個對象引用變量修改了這個對象的內部狀態,那么另一個對象引用變量也即刻反映出這個變化。相反,通過字面值的引用來修改其值,不會導致另一個指向此字面值的引用的值也跟著改變的情況。如上例,我們定義完a與b的值后,再令a=abcd;那么,b不會等于abcd,還是等于abc。在編譯器內部,遇到a= abcd;時,它就會重新搜索棧中是否有abcd的字面值,如果沒有,重新開辟地址存放abcd的值;如果已經有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。堆內存:堆內存用來存放所有new 創建的對象和 數組的數據、1. String a = new String ("abc");2. String b = "abc";3. System.out.println(a==b);  //False4. String a = new String ("abc");5. String b = new String ("abc");6. System.out.println(a==b);  //False創建了兩個引用。創建了兩個對象。兩個引用分別指向不同的兩個對象。以上兩段代碼說明,只要是用new()來新建對象的,都會在堆中創建,而且其字符串是單獨存值的,即使與棧中的數據相同,也不會與棧中的數據共享。6.try {}里有一個return語句,那么緊跟在這個try后的finally {}里的code會不會被執行,什么時候被執行,在return前還是后?你中招了……話說當年某天才還開玩笑說用這個例子做筆試題拿去面試的,后來不知道有沒有真用。《深入Java虛擬機》里有詳細說明,先執行return,把結果緩存起來,然后再執行finally,最終返回緩存的結果。7.下面這條語句一共創建了多少個對象:String s="a"+"b"+"c"+"d";對于如下代碼:String s1 = "a";String s2 = s1 + "b";String s3 = "a" + "b";System.out.println(s2 == "ab");System.out.println(s3 == "ab");第一條語句打印的結果為false,第二條語句打印的結果為true,這說明javac編譯可以對字符串常量直接相加的表達式進行優化,不必要等到運行期去進行加法運算處理,而是在編譯時去掉其中的加號,直接將其編譯成一個這些常量相連的結果。題目中的第一行代碼被編譯器在編譯時優化后,相當于直接定義了一個”abcd”的字符串,所以,上面的代碼應該只創建了一個String對象。寫如下兩行代碼,String s ="a" + "b" + "c" + "d";System.out.println(s== "abcd");最終打印的結果應該為true。來源: http://blog.sina.com.cn/s/blog_8f329b7b0101nkh2.html8. 數組有沒有length()這個方法? String有沒有length()這個方法?數組沒有length()這個方法,有length的屬性。String有有length()這個方法9. Anonymous Inner Class(匿名內部類)是否可以 extends(繼承)其它類,是否可以 implements(實現)interface(接口)?1、什么是匿名內部類?內部類,存在于另一個類內部的類,而匿名內部類,顧名思義,就是沒有名字的內部類。2、為什么需要匿名內部類?每個inner class都能夠各自繼承某一實現類(implementation)。因此,inner class不受限于outer class是否已繼承自某一實現類。如果少了inner class所提供的“繼承自多個具象(concrete)或抽象(abstract)類”的能力,設計上和編程上的某些問題會變得十分棘手。所以,從某個角度來看inner class,你可以說它是多重繼承問題的完整解決方案。interface能夠解決其中一部分問題,但inner classes才能有效而實際地允許“多重實現繼承(multiple implementation)”。也就是說,inner classes實際上允許你繼承多個non-interface。從這個層面上使用內部類時一般都是通過其父類或繼承的接口來進行實例化和初始化的,如3中所示,這時內部類的名字是多余的,所以就使用了匿名內部類3、怎么實現匿名內部類?匿名內部類的實現非常簡單,如有一接口Interface A{public void method();}這時你可以寫一個如下的語句得到接口A的實現類的對象A a=new A(){ public void method(){System.out.println("hehe");} };而其中的{ public void method(){System.out.println("hehe");} };就是定義了一個匿名內部類4、問題答案以上可以看出匿名內部類在實現時必須借助一個類或一個接口,若從這個層次上講它是可以繼承其他類也可以實現接口的,但若是通過extends或implements關鍵字那是不可能的來源: http://blog.csdn.net/fhm727/article/details/522000310. 什么是內部類?Static Nested Class 和 Inner Class 的不同。Inner Class(內部類)定義在類中的類。 (一般是JAVA的說法)Nested Class(嵌套類)是靜態(static)內部類。(一般是C++的說法)靜態內部類:1 創建一個 static 內部類的對象,不需要一個外部類對象2 不能從一個 static 內部類的一個對象訪問一個外部類對象Java 內部類與C++嵌套類最大的不同就在于是否有指向外部的引用上。內部類:就是在一個類的內部定義的類,A.非靜態內部類中不能定義靜態成員(靜態對象是默認加載,那么靜態內部類應該先于外部類被加載到內存中)當內部類中如果有靜態成員時,該內部類也必須是靜態的。而靜態內部類只能訪問外部類中的靜態成員。 會出現兩種情況:1,內部類靜態,但是方法沒靜態。該方法需要被對象調用執行。Outer.Inner in = new Outer.Inner();//產生了一個靜態內部類對象。in.show();2,內部類靜態,而且方法也是靜態的。靜態內部類隨著對象的加載就已經存在了,靜態方法隨著內部類的加載也存在了。這時是不需要對象的。Outer1.Inner.show();B.內部類可以直接訪問外部類中的成員變量非靜態的內部類之所以可以直接訪問外部類中的成員,那是因為內部類中都持有一個外部類對象引用:外部類名.this.變量名靜態內部類之所以可以直接訪問外部類中的靜態成員,其實持有的是外部類名。C.內部類可以定義在外部類的方法外面,也可以定義在外部類的方法體中,如下所示:public class Outer{int out_x = 0;public void method(){Inner1 inner1 = new Inner1();class Inner2{ //在方法體內部定義的內部類void method(){out_x = 3;}}Inner2 inner2 = new Inner2();}public class Inner1{ //在方法體外面定義的內部類}在方法體外面定義的內部類的訪問類型可以是 public,protected,默認的,private等4種類型,它們決定這個內部類的定義對其他類是否可見;對于這種情況,我們也可以在外面創建內部類的實例對象,一定要先創建外部類的實例對象,然后用這個外部類的實例對象去創建內部類的實例對象,代碼如下:Outer outer = new Outer();Outer.Inner1 inner1 = outer.new Innner1();在方法內部定義的內部類前面不能有訪問類型修飾符,但前面可以使用 final 或 abstract 修飾符。這種內部類對其他類是不可見的其他類無法引用這種內部類,但是這種內部類創建的實例對象可以傳遞給其他類訪問。這種內部類必須是先定義,后使用,即內部類的定義代碼必須出現在使用該類之前,這與方法中的局部變量必須先定義后使用的道理也是一樣的。這種內部類可以訪問方法體中的局部變量,但是,該局部變量前必須加 final 修飾符。在方法體內部還可以采用如下語法來創建一種匿名內部類,沒有名字的內部類,即定義某一接口或類的子類的同時,還創建了該子類的實例對象,無需為該子類定義名稱:public class Outer{public void start(){new Thread(new Runable(){public void run(){};}).start();}}Static Nested Class,它不再具有內部類的特性,從狹義上講,它不是內部類。Static Nested Class 與普通類在運行時的行為和功能上沒有什么區別,只是在編程引用時的語法上有一些差別:1.它可以定義成public、protected、默認的、private 等多種類型,而普通類只能定義成 public 和默認 的這兩種類型。2.在外面引用Static Nested Class 類的名稱為“外部類名.內部類名”。3.在外面不需要創建外部類的實例對象,就可以直接創建 Static Nested Class,例如,假設 Inner 是定義在 Outer 類中的 Static Nested Class,那么可以使用如下語句創建 Inner 類:Outer.Inner inner = new Outer.Inner();4.由于static Nested Class 不依賴于外部類的實例對象,所以,static Nested Class 能訪問外部類的非 static 成員變量。5.當在外部類中訪問Static Nested Class 時,可以直接使用 Static Nested Class 的名字,而不需要加上外部類的名字了,在 Static Nested Class 中也可以直接引用外部類的 static 的成員變量,不需要加上外部類的名字。在靜態方法中定義的內部類也是 Static Nested Class,這時候不能在類前面加 static 關鍵字,靜態方法中的 Static Nested Class 與普通方法中的內部類的應用方式很相似,它除了可以直接訪問外部類中的 static 的成員變量,還可以訪問靜態方法中的局部變量,但是,該局部變量前必須加 final 修飾符。備注:內部類的總體方面的特點:兩個地方可以定義,可以訪問外部類的成員變量,不能定義靜態成員,這是大的特點。然后再說一些細節方面的知識,例如,幾種定義方式的語法區別,靜態內部類,以及匿名內部類。11. 什么是java序列化?如何實現java序列化?或者請解釋Serializable接口的作用。將一個 java 對象變成字節流的形式傳出去或者從一個字節流中恢復成一個 java 對象序列化是將對象狀態轉換為可保持或傳輸的格式的過程。java 中的序列化機制能夠將一個實例對象(只序列化對象的屬性值,而不會去序列化什么所謂的方法。)的狀態信息寫入到一個字節流中使其可以通過 socket 進行傳輸、或者持久化到存儲數據庫或文件系統中;然后在需要的時候通過字節流中的信息來重構一個相同的對象。一般而言,要使得一個類可以序列化,只需簡單實現 java.io.Serializable 接口即可。序列化就是一種用來處理對象流的機制,所謂對象流也就是將對象的內容進行流化。可以對流化后的對象進行讀寫操作,也可將流化后的對象傳輸于網絡之間。序列化是為了解決在對對象流進行讀寫操作時所引發的問題。    序列化的實現:將需要被序列化的類實現 Serializable 接口,該接口沒有需要實現的方法,implements Serializable 只是為了標注該對象是可被序列化的,然后使用一個輸出流(如:FileOutputStream )來構造一個 ObjectOutputStream (對象流)對象,接著,使用 ObjectOutputStream 對象的 writeObject(Object obj) 方法就可以將參數為 obj 的對象寫出(即保存其狀態),要恢復的話則用輸入流。12. 運行時異常與一般異常有何異同運行時異常和非運行時異常(1)運行時異常都是 RuntimeException 類及其子類異常,如 NullPointerException、IndexOutOfBoundsException 等,這些異常是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。這些異常一般是由程序邏輯錯誤引起的,程序應該從邏輯角度盡可能避免這類異常的發生。當出現 RuntimeException 的時候,我們可以不處理。當出現這樣的異常時,總是由虛擬機接管。比如:我們從來沒有人去處理過 NullPointerException 異常,它就是運行時異常,并且這種異常還是最常見的異常之一。出現運行時異常后,如果沒有捕獲處理這個異常(即沒有 catch),系統會把異常一直往上層拋,一直到最上層,如果是多線程就由 Thread.run() 拋出,如果是單線程就被 main()拋出。拋出之后,如果是線程,這個線程也就退出了。如果是主程序拋出的異常,那么這整個程序也就退出了。運行時異常是 Exception 的子類,也有一般異常的特點,是可以被 catch 塊處理的。只不過往往我們不對他處理罷了。也就是說,你如果不對運行時異常進行處理,那么出現運行時異常之后,要么是線程中止,要么是主程序終止。如果不想終止,則必須捕獲所有的運行時異常,決不讓這個處理線程退出。隊列里面出現異常數據了,正常的處理應該是把異常數據舍棄,然后記錄日志。不應該由于異常數據而影響下面對正常數據的處理。(2)非運行時異常是 RuntimeException 以外的異常,類型上都屬于 Exception 類及其子類。如 IOException、SQLException 等以及用戶自定義的 Exception 異常。對于這種異常,JAVA 編譯器強制要求我們必需對出現的這些異常進行 catch 并處理,否則程序就不能編譯通過。所以,面對這種異常不管我們是否愿意,只能自己去寫一大堆 catch 塊去處理可能的異常。13. Java 的接口和 C++ 的虛類的相同和不同處C++虛類相當與 java 里面的抽象類,與接口的不同之處如下:1、一個子類只能繼承一個抽象類(虛類),但能實現多個接口;2、一個抽象類可以有構造方法,接口沒有構造方法;3、一個抽象類中的方法不一定是抽象方法,即其中的方法可以有實現(有方法體),接口中的方法都是抽象方法,不能有方法體,只有聲明;4、一個抽象類可以是 public、private、protected、default,接口只有 public;5、一個抽象類中的方法可以是 public、private、protected、default,接口中的方法只能是 public 和 default.相同之處:都不能實例化。補充說明:接口是一類特殊的抽象類,是更抽象的抽象類,你可能這樣理解。抽象類是一個不完整的類,接口只是定義了一些功能。打個比方,用抽象類和接口分別描述“豬”,抽象類就是在一般的類之前加 abstract ,說:豬能用四肢跑,豬還能怎么怎么,接口的話只能說,豬會跑,用什么跑就是子類的事啦。14. swtich 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上在 switch(expr1)中,expr1只能是一個整數表達式或者枚舉常量(更大字體),整數表達式可以是 int 基本類型或 Integer 包裝類型,由于,byte,short,char 都可以隱含轉換為 int,所以,這些類型以及這些類型的包裝類型也是可以的。顯然,long 和 String 類型都不符合 switch 的語法規定,并且不能被隱式轉換成 int 類型,所以,它們不能作用于 switch 語句中。Java 7中,switch的參數可以是String類型了15. 當一個對象被當作參數傳遞到一個方法后,此方法可改變這個對象的屬性,并可返回變化后的結果,那么這里到底是值傳遞還是引用傳遞是值傳遞。Java 編程語言只有值傳遞參數。當一個對象實例作為一個參數被傳遞到方法中時,參數的值就是該對象的引用一個副本。指向同一個對象,對象的內容可以在被調用的方法中改變,但對象的引用(不是引用的副本)是永遠不會改變的。-------------------------------------------------------------在 Java 應用程序中永遠不會傳遞對象,而只傳遞對象引用。因此是按引用傳遞對象。但重要的是要區分參數是如何傳遞的,這才是該節選的意圖。Java 應用程序按引用傳遞對象這一事實并不意味著 Java 應用程序按引用傳遞參數。參數可以是對象引用,而 Java 應用程序是按值傳遞對象引用的。  Java 應用程序中的變量可以為以下兩種類型之一:引用類型或基本類型。當作為參數傳遞給一個方法時,處理這兩種類型的方式是相同的。兩種類型都是按值傳遞的;沒有一種按引用傳遞。   按 值傳遞意味著當將一個參數傳遞給一個函數時,函數接收的是原始值的一個副本。因此,如果函數修改了該參數,僅改變副本,而原始值保持不變。按引用傳遞意味 著當將一個參數傳遞給一個函數時,函數接收的是原始值的內存地址,而不是值的副本。因此,如果函數修改了該參數的值,調用代碼中的原始值也隨之改變。如果 函數修改了該參數的地址,調用代碼中的原始值不會改變.   當傳遞給函數的參數不是引用時,傳遞的都是該值的一個副本(按值傳遞)。區別在于引用。在 C++ 中當傳遞給函數的參數是引用時,您傳遞的就是這個引用,或者內存地址(按引用傳遞)。在 Java 應用程序中,當對象引用是傳遞給方法的一個參數時,您傳遞的是該引用的一個副本(按值傳遞),而不是引用本身。   Java 應用程序按值傳遞參數(引用類型或基本類型),其實都是傳遞他們的一份拷貝.而不是數據本身.(不是像 C++ 中那樣對原始值進行操作。)來源: http://xinklabi.iteye.com/blog/199610516. 兩個對象值相同 (x.equals(y) == true) ,但卻可有不同的 hashcode ,這句話對不對?對。如果對象要保存在HashSet或HashMap中,它們的equals相等,那么,它們的hashcode值就必須相等。如果不是要保存在HashSet或HashMap,則與hashcode沒有什么關系了,這時候hashcode不等是可以的,例如arrayList存儲的對象就不用實現hashcode,當然,我們沒有理由不實現,通常都會去實現的。四、集合、容器、泛型等1. 集合框架中的泛型有什么優點?Java1.5引入了泛型,所有的集合接口和實現都大量地使用它。泛型允許我們為集合提供一個可以容納的對象類型,因此,如果你添加其它類型的任何元素,它會在編譯時報錯。這避免了在運行時出現ClassCastException,因為你將會在編譯時得到報錯信息。泛型也使得代碼整潔,我們不需要使用顯式轉換和instanceOf操作符。它也給運行時帶來好處,因為不會產生類型檢查的字節碼指令。2. 你所知道的集合類都有哪些?主要方法?線性表,鏈表,哈希表是常用的數據結構,在進行Java開發時,JDK已經為我們提供了一系列相應的類來實現基本的數據結構。這些類均在java.util包中。本文試圖通過簡單的描述,向讀者闡述各個類的作用以及如何正確使用這些類。Collection├List│├LinkedList│├ArrayList│└Vector│ └Stack└SetMap├Hashtable├HashMap└WeakHashMapCollection接口Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)。一些Collection允許相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接繼承自Collection的類,Java SDK提供的類都是繼承自Collection的“子接口”如List和Set。所有實現Collection接口的類都必須提供兩個標準的構造函數:無參數的構造函數用于創建一個空的Collection,有一個Collection參數的構造函數用于創建一個新的Collection,這個新的Collection與傳入的Collection有相同的元素。后一個構造函數允許用戶復制一個Collection。如何遍歷Collection中的每一個元素?不論Collection的實際類型如何,它都支持一個iterator()的方法,該方法返回一個迭代子,使用該迭代子即可逐一訪問Collection中每一個元素。典型的用法如下:Iterator it = collection.iterator(); // 獲得一個迭代子while(it.hasNext()) {Object obj = it.next(); // 得到下一個元素}由Collection接口派生的兩個接口是List和Set。List接口List是有序的Collection,使用此接口能夠精確的控制每個元素插入的位置。用戶能夠使用索引(元素在List中的位置,類似于數組下標)來訪問List中的元素,這類似于Java的數組。和下面要提到的Set不同,List允許有相同的元素。除了具有Collection接口必備的iterator()方法外,List還提供一個listIterator()方法,返回一個ListIterator接口,和標準的Iterator接口相比,ListIterator多了一些add()之類的方法,允許添加,刪除,設定元素,還能向前或向后遍歷。實現List接口的常用類有LinkedList,ArrayList,Vector和Stack。LinkedList類LinkedList實現了List接口,允許null元素。此外LinkedList提供額外的get,remove,insert方法在LinkedList的首部或尾部。這些操作使LinkedList可被用作堆棧(stack),隊列(queue)或雙向隊列(deque)。注意LinkedList沒有同步方法。如果多個線程同時訪問一個List,則必須自己實現訪問同步。一種解決方法是在創建List時構造一個同步的List:List list = Collections.synchronizedList(new LinkedList(...));ArrayList類ArrayList實現了可變大小的數組。它允許所有元素,包括null。ArrayList沒有同步。size,isEmpty,get,set方法運行時間為常數。但是add方法開銷為分攤的常數,添加n個元素需要O(n)的時間。其他的方法運行時間為線性。每個ArrayList實例都有一個容量(Capacity),即用于存儲元素的數組的大小。這個容量可隨著不斷添加新元素而自動增加,但是增長算法并沒有定義。當需要插入大量元素時,在插入前可以調用ensureCapacity方法來增加ArrayList的容量以提高插入效率。和LinkedList一樣,ArrayList也是非同步的(unsynchronized)。Vector類Vector非常類似ArrayList,但是Vector是同步的。由Vector創建的Iterator,雖然和ArrayList創建的Iterator是同一接口,但是,因為Vector是同步的,當一個Iterator被創建而且正在被使用,另一個線程改變了Vector的狀態(例如,添加或刪除了一些元素),這時調用Iterator的方法時將拋出ConcurrentModificationException,因此必須捕獲該異常。Stack 類Stack繼承自Vector,實現一個后進先出的堆棧。Stack提供5個額外的方法使得Vector得以被當作堆棧使用。基本的push和pop方法,還有peek方法得到棧頂的元素,empty方法測試堆棧是否為空,search方法檢測一個元素在堆棧中的位置。Stack剛創建后是空棧。Set接口Set是一種不包含重復的元素的Collection,即任意的兩個元素e1和e2都有e1.equals(e2)=false,Set最多有一個null元素。很明顯,Set的構造函數有一個約束條件,傳入的Collection參數不能包含重復的元素。請注意:必須小心操作可變對象(Mutable Object)。如果一個Set中的可變元素改變了自身狀態導致Object.equals(Object)=true將導致一些問題。Map接口請注意,Map沒有繼承Collection接口,Map提供key到value的映射。一個Map中不能包含相同的key,每個key只能映射一個value。Map接口提供3種集合的視圖,Map的內容可以被當作一組key集合,一組value集合,或者一組key-value映射。Hashtable類Hashtable繼承Map接口,實現一個key-value映射的哈希表。任何非空(non-null)的對象都可作為key或者value。添加數據使用put(key, value),取出數據使用get(key),這兩個基本操作的時間開銷為常數。Hashtable通過initial capacity和load factor兩個參數調整性能。通常缺省的load factor 0.75較好地實現了時間和空間的均衡。增大load factor可以節省空間但相應的查找時間將增大,這會影響像get和put這樣的操作。使用Hashtable的簡單示例如下,將1,2,3放到Hashtable中,他們的key分別是”one”,”two”,”three”:Hashtable numbers = new Hashtable();numbers.put(“one”, new Integer(1));numbers.put(“two”, new Integer(2));numbers.put(“three”, new Integer(3));要取出一個數,比如2,用相應的key:Integer n = (Integer)numbers.get(“two”);System.out.println(“two = ” + n);由于作為key的對象將通過計算其散列函數來確定與之對應的value的位置,因此任何作為key的對象都必須實現hashCode和equals方法。hashCode和equals方法繼承自根類Object,如果你用自定義的類當作key的話,要相當小心,按照散列函數的定義,如果兩個對象相同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一定不同,如果兩個不同對象的hashCode相同,這種現象稱為沖突,沖突會導致操作哈希表的時間開銷增大,所以盡量定義好的hashCode()方法,能加快哈希表的操作。如果相同的對象有不同的hashCode,對哈希表的操作會出現意想不到的結果(期待的get方法返回null),要避免這種問題,只需要牢記一條:要同時復寫equals方法和hashCode方法,而不要只寫其中一個。Hashtable是同步的。HashMap類HashMap和Hashtable類似,不同之處在于HashMap是非同步的,并且允許null,即null value和null key。,但是將HashMap視為Collection時(values()方法可返回Collection),其迭代子操作時間開銷和HashMap的容量成比例。因此,如果迭代操作的性能相當重要的話,不要將HashMap的初始化容量設得過高,或者load factor過低。WeakHashMap類WeakHashMap是一種改進的HashMap,它對key實行“弱引用”,如果一個key不再被外部所引用,那么該key可以被GC回收。總結如果涉及到堆棧,隊列等操作,應該考慮用List,對于需要快速插入,刪除元素,應該使用LinkedList,如果需要快速隨機訪問元素,應該使用ArrayList。如果程序在單線程環境中,或者訪問僅僅在一個線程中進行,考慮非同步的類,其效率較高,如果多個線程可能同時操作一個類,應該使用同步的類。要特別注意對哈希表的操作,作為key的對象要正確復寫equals和hashCode方法。盡量返回接口而非實際的類型,如返回List而非ArrayList,這樣如果以后需要將ArrayList換成LinkedList時,客戶端代碼不用改變。這就是針對抽象編程。3. Comparable和Comparator接口是什么?Comparable和Comparator接口有何區別?http://www.cnblogs.com/skywang12345/p/3324788.html4. ArrayList 和 Vector 的區別 ,HashMap 和 Hashtable的區別這兩個類都實現了List接口(List接口繼承了Collection接口),他們都是有序集合,即存儲在這兩個集合中的元素的位置都是有順序的,相當于一種動態的數組,我們以后可以按位置索引號取出某個元素,,并且其中的數據是允許重復的,這是HashSet之類的集合的最大不同處,HashSet之類的集合不可以按索引號去檢索其中的元素,也不允許有重復的元素(本來題目問的與hashset沒有任何關系,但為了說清楚ArrayList與Vector的功能,我們使用對比方式,更有利于說明問題)。接著才說ArrayList與Vector的區別,這主要包括兩個方面:.(1)同步性:Vector是線程安全的,也就是說是它的方法之間是線程同步的,而ArrayList是線程序不安全的,它的方法之間是線程不同步的。如果只有一個線程會訪問到集合,那最好是使用ArrayList,因為它不考慮線程安全,效率會高些;如果有多個線程會訪問到集合,那最好是使用Vector,因為不需要我們自己再去考慮和編寫線程安全的代碼。備注:對于Vector&ArrayList、Hashtable&HashMap,要記住線程安全的問題,記住Vector與Hashtable是舊的,是java一誕生就提供了的,它們是線程安全的,ArrayList與HashMap是java2時才提供的,它們是線程不安全的。所以,我們講課時先講老的。(2)數據增長:ArrayList與Vector都有一個初始的容量大小,當存儲進它們里面的元素的個數超過了容量時,就需要增加ArrayList與Vector的存儲空間,每次要增加存儲空間時,不是只增加一個存儲單元,而是增加多個存儲單元,每次增加的存儲單元的個數在內存空間利用與程序效率之間要取得一定的平衡。Vector默認增長為原來兩倍,而ArrayList的增長策略在文檔中沒有明確規定(從源代碼看到的是增長為原來的1.5倍)。ArrayList與Vector都可以設置初始的空間大小,Vector還可以設置增長的空間大小,而ArrayList沒有提供設置增長空間的方法。總結:即Vector增長原來的一倍,ArrayList增加原來的0.5倍。HashMap和Hashtable的區別(條理上還需要整理,也是先說相同點,再說不同點)HashMap是Hashtable的輕量級實現(非線程安全的實現),他們都完成了Map接口,主要區別在于HashMap允許空(null)鍵值(key),由于非線程安全,在只有一個線程訪問的情況下,效率要高于Hashtable。HashMap允許將null作為一個entry的key或者value,而Hashtable不允許。HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因為contains方法容易讓人引起誤解。Hashtable繼承自Dictionary類,而HashMap是Java1.2引進的Map interface的一個實現。最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多個線程訪問Hashtable時,不需要自己為它的方法實現同步,而HashMap 就必須為之提供外同步。Hashtable和HashMap采用的hash/rehash算法都大概一樣,所以性能不會有很大的差異。就HashMap與HashTable主要從三方面來說。一.歷史原因:Hashtable是基于陳舊的Dictionary類的,HashMap是Java 1.2引進的Map接口的一個實現二.同步性:Hashtable是線程安全的,也就是說是同步的,而HashMap是線程序不安全的,不是同步的三.值:只有HashMap可以讓你將空值作為一個表的條目的key或value五、網絡編程1. 使用TCP建立交互方式客戶端1. public class ClientDemo2 {2. /**3. * @param args4. * @throws IOException5. * @throws UnknownHostException6. */7. public static void main(String[] args) throws UnknownHostException, IOException {8. // 客戶端發數據到服務端9. /*10. * Tcp傳輸,客戶端建立的過程。 1,創建tcp客戶端socket服務。使用的是Socket對象。11. * 建議該對象一創建就明確目的地。要連接的主機。 2,如果連接建立成功,說明數據傳輸通道已建立。 該通道就是socket流 ,是底層建立好的。12. * 既然是流,說明這里既有輸入,又有輸出。 想要輸入或者輸出流對象,可以找Socket來獲取。13. * 可以通過getOutputStream(),和getInputStream()來獲取兩個字節流。 3,使用輸出流,將數據寫出。14. * 4,關閉資源。15. */16. Socket socket = new Socket("192.168.1.100", 10002);17. OutputStream out = socket.getOutputStream();18. out.write("tcp演示:哥們又來了!".getBytes());19. // 讀取服務端返回的數據,使用socket讀取流。20. InputStream in = socket.getInputStream();21. byte[] buf = new byte[1024];22. int len = in.read(buf);23. String text = new String(buf, 0, len);24. System.out.println(text);25. // 關閉資源。26. socket.close();27. }28. }服務端1. public class ServerDemo2 {2. /**3. * @param args4. * @throws IOException5. */6. public static void main(String[] args) throws IOException {7. // 服務端接收客戶端發送過來的數據,并打印在控制臺上。8. /*9. * 建立tcp服務端的思路: 1,創建服務端socket服務。通過ServerSocket對象。10. * 2,服務端必須對外提供一個端口,否則客戶端無法連接。 3,獲取連接過來的客戶端對象。11. * 4,通過客戶端對象獲取socket流讀取客戶端發來的數據 并打印在控制臺上。 5,關閉資源。關客戶端,關服務端。12. */13. // 1創建服務端對象。14. ServerSocket ss = new ServerSocket(10002);15. // 2,獲取連接過來的客戶端對象。16. Socket s = ss.accept();17. String ip = s.getInetAddress().getHostAddress();18. // 3,通過socket對象獲取輸入流,要讀取客戶端發來的數據19. InputStream in = s.getInputStream();20. byte[] buf = new byte[1024];21. int len = in.read(buf);22. String text = new String(buf, 0, len);23. System.out.println(ip + ":" + text);24. // 使用客戶端socket對象的輸出流給客戶端返回數據25. OutputStream out = s.getOutputStream();26. out.write("收到".getBytes());27. s.close();28. ss.close();29. }30. }2. 聊天程序(多線程)發送端1. public class Send implements Runnable {2. private DatagramSocket ds;3. 4. public Send(DatagramSocket ds) {5. this.ds = ds;6. }7. 8. @Override9. public void run() {10. try {11. BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));12. String line = null;13. while ((line = bufr.readLine()) != null) {14. byte[] buf = line.getBytes();15. DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.255"), 10001);16. ds.send(dp);17. if ("886".equals(line))18. break;19. }20. ds.close();21. } catch (Exception e) {22. }23. }24. }接收端1. public class Rece implements Runnable {2. private DatagramSocket ds;3. 4. public Rece(DatagramSocket ds) {5. this.ds = ds;6. }7. 8. @Override9. public void run() {10. try {11. while (true) {12. // 2,創建數據包。13. byte[] buf = new byte[1024];14. DatagramPacket dp = new DatagramPacket(buf, buf.length);15. // 3,使用接收方法將數據存儲到數據包中。16. ds.receive(dp);// 阻塞式的。17. // 4,通過數據包對象的方法,解析其中的數據,比如,地址,端口,數據內容。18. String ip = dp.getAddress().getHostAddress();19. int port = dp.getPort();20. String text = new String(dp.getData(), 0, dp.getLength());21. System.out.println(ip + "::" + text);22. if (text.equals("886")) {23. System.out.println(ip + "....退出聊天室");24. }25. }26. } catch (Exception e) {27. }28. }29. }開啟發送和接收兩個線程開始運行聊天  1. public class ChatDemo {2. /**3. * @param args4. * @throws IOException5. */6. public static void main(String[] args) throws IOException {7. DatagramSocket send = new DatagramSocket();8. DatagramSocket rece = new DatagramSocket(10001);9. new Thread(new Send(send)).start();10. new Thread(new Rece(rece)).start();11. }12. }3. 使用UDP建立信息接收端1. public class UDPReceDemo {2. /**3. * @param args4. * @throws IOException5. */6. public static void main(String[] args) throws IOException {7. System.out.println("接收端啟動......");8. /*9. * 建立UDP接收端的思路。 1,建立udp socket服務,因為是要接收數據,必須要明確一個端口號。10. * 2,創建數據包,用于存儲接收到的數據。方便用數據包對象的方法解析這些數據.11. * 3,使用socket服務的receive方法將接收的數據存儲到數據包中。 4,通過數據包的方法解析數據包中的數據。 5,關閉資源12. */13. // 1,建立udp socket服務。14. DatagramSocket ds = new DatagramSocket(10000);15. // 2,創建數據包。16. byte[] buf = new byte[1024];17. DatagramPacket dp = new DatagramPacket(buf, buf.length);18. // 3,使用接收方法將數據存儲到數據包中。19. ds.receive(dp);// 阻塞式的。20. // 4,通過數據包對象的方法,解析其中的數據,比如,地址,端口,數據內容。21. String ip = dp.getAddress().getHostAddress();22. int port = dp.getPort();23. String text = new String(dp.getData(), 0, dp.getLength());24. System.out.println(ip + ":" + port + ":" + text);25. // 5,關閉資源。26. ds.close();27. }28. }4. 使用UDP建立信息發送端1. public class UDPSendDemo {2.    /**3.     * @param args4.     * @throws IOException5.     */6.    public static void main(String[] args) throws IOException {7.        System.out.println("發送端啟動......");8.        /*9.         * 創建UDP傳輸的發送端。 思路: 1,建立udp的socket服務。 2,將要發送的數據封裝到數據包中。10.         * 3,通過udp的socket服務將數據包發送出去。 4,關閉socket服務。11.         */12.        // 1,udpsocket服務。使用DatagramSocket對象。13.        DatagramSocket ds = new DatagramSocket(8888);14.        // 2,將要發送的數據封裝到數據包中。15.        String str = "udp傳輸演示:哥們來了! ";16.        // 使用DatagramPacket將數據封裝到的該對象包中。17.        byte[] buf = str.getBytes();18.        DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.100"), 10000);19.        // 3,通過udp的socket服務將數據包發送出去。使用send方法。20.        ds.send(dp);21.        // 4,關閉資源。22.        ds.close();23.    }24. }
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 廊坊市| 汶上县| 龙山县| 将乐县| 宁夏| 大田县| 金湖县| 平昌县| 和顺县| 宜都市| 昌黎县| 托克托县| 夹江县| 伊吾县| 北碚区| 昂仁县| 昆明市| 汝城县| 富阳市| 广宗县| 广州市| 井研县| 文化| 微山县| 紫金县| 安龙县| 剑河县| 镇雄县| 丰都县| 防城港市| 六盘水市| 肥乡县| 澄江县| 扬中市| 徐汇区| 红原县| 东方市| 郑州市| 郧西县| 焦作市| 黑龙江省|