Java進階練習題整理(1)

小島的每一段verse發表於2021-08-09

1. 檢查時異常、非檢查時異常、執行時異常。

 

 

 

 

 

 

 

 

 

Throwable是一切異常、錯誤類的超類,Throwable有兩個子類,Error(錯誤)和Exception(異常)。
Exception異常又分為RuntimeException執行時異常(非檢查時異常)、檢查時異常和非檢查時異常。
執行時異常是在開發中測試功能時程式終止,控制檯出現的異常。
執行時異常有:空指標異常、下標越界異常、類轉換異常、資料儲存異常、快取快取異常、非法引數異常、算術運算異常、陣列儲存異常、大小為負數的陣列錯誤異常、數字格式異常、不支援的操作異常、安全異常。
InputMismatchException:Scanner輸入不符合型別的執行時異常。
ClassCastException:強制轉換時不通過的執行時異常
執行時異常表示虛擬機器的通常操作中可能遇到的異常。

檢查時異常是RuntimeException以外的異常,從程式語法角度講師必須進行處理的異常,如果不處理,程式就不能編譯通過。檢查時異常就是寫程式碼時出現紅線,需要try-catch 或者throws時出現的異常。
檢查時異常有IO異常、SQL異常。
非檢查時異常:
ClassNotFoundException:是非檢查時異常。反射時出現的型別找不到異常。當動態載入Class的時候找不到類會丟擲該異常 。一般在執行Class.forName()、ClassLoader.loadClass()或ClassLoader.findSystemClass()的時候丟擲

 

 

 

序列化的含義:
講一個物件的狀態(各個屬性量)儲存起來,然後再適當的時候再獲得。
所以static和transient修飾的變數不能被序列化。原因是static修飾的是變數描述類的狀態,transient修飾變數不能被持久化(序列化),代表臨時資料。
序列化的過程:
部分一:序列化:將資料分為位元組流,以便儲存在檔案或網路上傳輸。
部分二:反序列化:開啟位元組流,並重構物件。
序列化的限制:
(1)只能對物件的狀態進行儲存,而不管物件的方法。
(2)當父類實現序列化,子類自動實現序列化,不需要顯示實現Serializable介面。
這就解釋了為什麼Exception的定義中,沒有實現Serialize介面,但是有序列化ID的原因。因為父類Throwable實現了Serialize介面。

public class Exception extends Throwable {
    static final long serialVersionUID = -3387516993124229948L;...}
    
public class Throwable implements Serializable {
    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -3042686055658047285L;}

3.異常程式碼題

class MyException extends Exception {
    MyException() {
    }
}

class AB {
    public void format() throws MyException {
        System.out.println("format()");
    }

    public int formatstr(String str) throws MyException {
        format();
        int i = Integer.valueOf(str);
        return i;
    }
}

 public class Test18 {
    public static void main(String[] args)  {
        new AB().formatstr("1");
    }
}

因為所給的程式碼中,Integer.valueOf()的字串引數是1,不會丟擲執行時異常NumberFormatException。所以只有一個會引起異常的點,就是呼叫丟擲了MyExcepption 異常的formatstr()的方法也要丟擲MyException。

A段:

public class TestRegularExperssion {
public void printA(float a,float b) throws SQLException{} }
public class TestRegularExpressionA extends TestRegularExperssion{ public void printA(float a,float b) throws NullPointerException{}
}

空指標異常是執行時異常,不是編譯時異常所以編譯器不會檢查。相當於子類沒有丟擲檢查時異常。所以可以看作,父類丟擲了檢查時異常,父類丟擲異常型別大於子類異常型別。

B段:

public class TestRegularExperssion {
public void printA(float a,float b)throws NullPointerException{} }
class TestRegularExpressionA extends TestRegularExperssion{ public void printA(float a,float b)throws SQLException{}
}

父類的方法丟擲異常型別必須大於等於子類丟擲異常型別。
所以應該在後面寫上:

class TestRegularExperssion {
public void printA(float a, float b) throws NullPointerException, SQLException {
}
}

class TestRegularExperssion {
    public void printA(float a, float b) throws NullPointerException, SQLException {
    }
}

C段:

public class TestRegularExperssion {
public void printA(float a,float b){} 
}
public class TestRegularExpressionA extends TestRegularExperssion{ 
public void printA(float a,float b)throws Exception{
super.printA(a,b); 
}
}

子類異常型別不能大於父類異常型別。

D段:

public class TestRegularExperssion {
public void printA(float a,float b)throws Exception{} 
}
public class TestRegularExpressionA extends TestRegularExperssion{ 
public void printA(float a,float b){
super.printA(a,b); }
}

super方法中丟擲了異常,而呼叫方沒有丟擲,編譯錯誤。
子類和父類重寫方法的異常關係:
如果子類丟擲了檢查時異常,那麼父類的檢查時異常類必須大於子類。
比如

 class TestRegularExperssion {
    public void printA(float a, float b) throws Exception {
    }
}
 class TestRegularExpressionA extends TestRegularExperssion {
    public void printA(float a, float b) throws SQLException {
    }
}

如果父類/子類丟擲的是執行時異常,不需要遵守這條規則。

4.集合

 

 

 

 

 

 

 

 

語法糖的含義和意義:
語法糖,意思是語法糖衣,是指新增某種語法,這種語法不會影響程式語言的功能。語法糖一般是為程式設計師提供方便,而不會提供實質性的功能改進。
泛型是什麼:
泛型是javaJDK1.5的新特性,它是引數化型別,可以用在類,介面,方法中分別稱為泛型類,泛型介面,泛型方法;
泛型的存在時期:
泛型存在於原始碼中,編譯後會變成原生型別/裸型別
List和List經過編譯後就變成了List和List(List和List)
所以說泛型技術就是一顆語法糖。
java中實現泛型的方法被稱為擦除型別,也叫做偽型別;
泛型擦除的意義:
Java 引入泛型擦除的原因是避免因為引入泛型而導致執行時建立不必要的類,避免過多的建立類而造成的執行時的過度消耗。

當泛型方法過載:

    public void method(List<Integer> list)
    {
        System.out.println("Integer");
    }
    public void method(List<String> list)
    {
        System.out.println("String");
    }

編譯會報錯,因為編譯期變成一樣的方法。

    public int method(List<Integer> list)
    {
        System.out.println("Integer");
        return 1;
    }
    public String method(List<String> list)
    {
        System.out.println("String");
        return "";
    }

編譯生成的位元組碼檔案中,只要描述符不一樣兩個方法就可以共存。所以不會報錯。

5.集合程式碼題

List<String> list = new ArrayList<String>();
        list.add("str1");
        list.add(2, "str2");
        String s = list.get(1);
        System.out.println(s);

IndexOutOfBoundsException: Index: 2, Size: 1

list的add(int idx,String str)方法必須在<size的地方放元素。不然會報下標越界異常。下標越界異常是執行時異常。

import java.util.List; 
public class Test {
public int getIndexofArray(float[] f){ 
int rtn=-1;
float objf=3.4; 
List list=null;
for(int i=0;i<f.size( );i++){ 
list.add(f[i]);
}
for(int i=0;i<list.size( );i++){ 
float tmp=(float)list.get(i); 
if(objf==tmp){rtn=i; }
}
return rtn; }
}

 其中共有()處錯誤
編譯時異常:2處
float objf=3.4; 應該是float objf=3.4f;
f.size( ); 應該是f.length
執行時異常:1處
空指標異常

public class Test {
public static void main(String[] args) { 
String[] argg={"a","1","b","8"}; 
Set s=new TreeSet();
s.addAll(Arrays.asList(argg)); 
System.out.println(s);
} }

預設升序(字典序、自然排序規則):
數字、大寫字母、小寫字母升序
(和Unicode碼的ASCII碼部分有關)
[(, 1, 8, :, A, B, a, b]
(為40,:為58

public class Test19{
    public static void main(String[] args) {
        List<String> list=new ArrayList<String>();
        list.add("hello");
        list.add("world");
        list.add("world");
        list.add(".");
        for(Iterator i=list.iterator();i.hasNext();){
            String s=i.next();
            System.out.print(s); }
    } }

如果是Iterator i = list.iterator();,返回的迭代器中的元素就是Object型別的。
所以上面的String s=i.next();會發生編譯錯誤,大轉小。
如果是Iterator i = list.iterator();,返回的迭代器中的元素就是E型別的。
Comparable重寫的compareTo()方法也是這樣的原理。

6.IO

 

Reader類的read()方法是從流中取出一個字元讀。
InputStream類的read()方法是從流中取出一個位元組讀。
Reader類過載的read()方法有:

 read(char[] cbuf, int off, int len)
 read(CharBuffer target) 
 read(java.nio.CharBuffer target)
 read(char cbuf[])

並沒有B選項的方法。
InputStream類過載的read()方法有:

 read(byte[] b, int off, int len)
 read(byte b[])

Writer類過載的write()方法有:

write(int c)
write(char cbuf[]) 
write(char[] cbuf, int off, int len)
write(String str)
write(String str, int off, int len)

 OutPutStream類過載的write()方法有:

write(int b) 
write(byte b[])
write(byte b[], int off, int len)

  

 

 

 

介面卡模式:使兩個介面不匹配而無法在一起工作的兩個類能夠在一起工作。
裝飾器模式:在原來介面的基礎上增加功能。
InputStreamReader是介面卡模式,因為它把位元組流轉換成了字元流
而BufferedInputStream是裝飾器模式,因為他在位元組流的基礎上新增了快取的功能。

 

當讀到流結尾時,會丟擲EOFException。

 

 

 

 Exception in thread “main” java.io.FileNotFoundException: d:\text1.txt (檔名、目錄名或卷標語法不正確。)

 

 

 位元組流一次讀一個位元組,字元流一次讀Unicode碼元(大小2位元組)。

7.IO程式碼題

public static void main(String[ ] args) { 
String str = "Hello World"; 
FileWriter fw = null;
try {
fw = new FileWriter("c:\\hello.txt"); // 1 fw.write(str);                     // 2
} catch (IOException e) {
e.printStackTrace();                // 3 } finally {
fw.close();                        // 4 }
}

4處會出現編譯錯誤,因為fw.close();方法會丟擲IO異常,所以要加上try塊包圍,在後面加上catch(IOException e){…}

 public static void main(String[] args) throws IOException {
        BufferedReader br =
                new BufferedReader(new FileReader("d:/text1.txt"));
        BufferedWriter bw =
                new BufferedWriter(new FileWriter("d:/text2.txt"));
        String str = br.readLine();
        while (str != null) {
            bw.write(str);
            bw.newLine();//根據作業系統選擇不同的換行符
            str = br.readLine();
        }
        br.close();
        bw.close();
    }

 

 

 

節點流:可以從或向一個特定的地方(節點)讀寫資料。如FileReader

處理流:是對一個已存在的流的連線和封裝,通過所封裝的流的功能呼叫實現資料讀寫。
如BufferedReader。處理流的構造方法總是要帶一個其他的流物件做引數。一個流物件經過其他流的多次包裝,稱為流的連結。

Reader、Writer、InputStream、OutputStream
常用節點流:
FileOutputStream…——從檔案的結點中讀寫
ByteArrayInputStream…——從陣列的節點中讀寫
StringReader——從字串的節點中讀寫(檔案節點流只有字元流)
PipedInputStream——從管道的節點中讀寫
常用處理流:
InputStreamReader…——轉換流
DataOutputStream…——資料流
PrintWriter、PrintStream——列印流
ObjectOutputStream——物件流

import java.io.*; public class A{
public static void main(String[] x){ 
String s="1234567890abcdefghijklmnopq"; 
byte[] b=s.getBytes();
try{
File f=new File("B.txt");
FileOutputStream out=new FileOutputStream(f); 
out.write(b,10,10);
out.write(b,0,5); 
}catch (IOException e){
System.out.println(e.getMessage()); 
}
} }

構造方法 FileOutputStream(f,true)表示本次輸出(流關閉之前),流中的資料向檔案中的內容追加。
追加與否,只考慮檔案原來的內容是否會保留。本次write()操作執行多少次,都會一直寫。

8.代理

 

 

靜態代理類:由程式設計師建立或由特定工具自動生成原始碼,再對其編譯。在程式執行前,代理類的.class檔案就已經存在了。
動態代理類:在程式執行時,運用反射機制動態建立而成。
代理類與被代理類具有相同的介面。
代理類是public、final的,不是abstract的
java.lang.reflect 包中的 Proxy 類提供了建立動態代理類的方法

 

E:動態代理有一個靜態public方法newProxyInstance(),負責建立動態代理類的例項,有一個InvocationHandler 型別的引數。

9.序列化

 

10.反射程式碼題

 

 首先,獲得制定反射方法物件的引數列表型別一定要完全一樣。
其次,Method.invoke()返回的是一個Object型別的返回值。

 

相關文章