天天看點

尚矽谷java入門356p-379p 面向對象和異常 2022.3.22

356p 接口練習:比較對象大小

尚矽谷java入門356p-379p 面向對象和異常 2022.3.22
/*
 * 定義一個接口用來實作兩個對象的比較。
 * 
 */
public interface CompareObject {
  public int compareTo(Object o);
  //若傳回值是 0,代表相等;若為正數,代表目前對象大;負數代表目前對象小
  
}

/*
 * 定義一個 Circle 類,聲明 redius 屬性,提供 getter 和 setter 方法
 */
public class Circle {
  
  private Double radius;

  public Double getRadius() {
    return radius;
  }

  public void setRadius(Double radius) {
    this.radius = radius;
  }

  public Circle() {
    super();
  }

  public Circle(Double radius) {
    super();
    this.radius = radius;
  }
    
}

/*
 * 定義一個 ComparableCircle 類,繼承 Circle 類并且實作 CompareObject 接口。在 ComparableCircle 類中給出接口中方法 compareTo 的實作體,
 * 用來比較兩個圓的半徑大小。
 */
public class ComparableCircle extends Circle implements CompareObject{

  public ComparableCircle(double radius) {
    super(radius);
  }
  @Override
  public int compareTo(Object o) {
    if(this == o){
      return 0;
    }
    if(o instanceof ComparableCircle){
      ComparableCircle c = (ComparableCircle)o;
      //錯誤的寫法
//      return (int)(this.getRedius() - c.getRedius());
      //正确的方式一:
//      if(this.getRadius() > c.getRadius()){
//        return 1;
//      }else if(this.getRadius() < c.getRadius()){
//        return -1;
//      }else{
//        return 0;
//      }
      //當屬性 radius 聲明為 Double 類型時,可以調用包裝類的方法
      //正确的方式二:
      return this.getRadius().compareTo(c.getRadius());
    }else{
      return 0;
//      throw new RuntimeException("傳入資料類型不比對");
    }
  }
}

/*
 * 定義一個測試類 InterfaceTest,建立兩個 ComparableCircle 對象,
 * 調用 compareTo 方法比較兩個類的半徑大小。
 * 
 */
public class InterfaceTest {
  public static void main(String[] args) {
    
    ComparableCircle c1 = new ComparableCircle(3.4);
    ComparableCircle c2 = new ComparableCircle(3.6);
    
    int compareValue = c1.compareTo(c2);
    if(compareValue > 0){
      System.out.println("c1 對象大");
    }else if(compareValue < 0){
      System.out.println("c2 對象大");
    }else{
      System.out.println("兩個一樣的");
    }
    
    int compareValue1 = c1.compareTo(new String("AA"));
    System.out.println(compareValue1);
  }
}      

357p java8中接口的新特性

 JDK8:除了定義全局變量和抽象方法之外,還可以定義靜态方法,預設方法

public interface CompareA{
  //靜态方法
  public static void method1(){
      System.out.println("CompareA:北京");
  }
  //預設方法
  public default void method2(){
      System.out.println("CompareA:上海");
  }
  default void method3(){
      System.out.println("CompareA:上海");
  }
}

public class SubClassTest{
   public static void main(String[] args){
       SubClass s=new SubClass();
       //s.method1;
       //SubClass.method1();
       //知識點1;接口中定義的靜态方法,隻能通過接口來調用
       CompareA.method1();
       //知識點2:通過實作類的對象,可以調用接口中的預設方法
       //如果實作類重寫了接口中的預設方法,調用時,仍然調用的是重寫以後的方法
       s.method2();
       //知識點3:如果子類(或實作類)繼承的父類和實作的接口中聲明了同名同參數的預設方法,
       //那麼子類在沒有重寫此方法的情況下,預設調用的是父類中同名同參數的方法---類優先原則
       //知識點4:如果實作類實作了多個接口,而這多個接口中定義了同名同參數的預設方法
       //那麼在實作類沒有重寫此方法的情況下,報錯---接口沖突
       //這就需要我們必須在實作類中重寫此方法
       s.method3();
       
   }
}
class SubClass extends SuperClass implements CompareA,CompareB{
   public void method2(){
      System.out.println("SubClass:上海");
  }
  public void method3(){
      System.out.println("SubClass:深圳");
  }
  //知識點5:如何在子類(或實作類)的方法中調用父類,接口中被重寫的方法
  public void myMethod(){
        method3();//自己定義的重寫的方法
        super.method3();//調用的是父類聲明的
        //調用接口中的預設方法
        CompareA.super.method3();
        CompareB.super.method3();
  }
}

public class SuperClass {
  public void method3(){
    System.out.println("SuperClass:北京");
  }
}

public interface CompareB{
  default void method3(){
      System.out.println("CompareB:上海");
  }
}      

358 java8接口新特性的應用 

/*
 * 練習:接口沖突的解決方式
 */
interface Filial {// 孝順的
  default void help() {
    System.out.println("老媽,我來救你了");
  }
}

interface Spoony {// 癡情的
  default void help() {
    System.out.println("媳婦,别怕,我來了");
  }
}

class Father{
  public void help(){
    System.out.println("兒子,救我媳婦!");
  }
}

class Man extends Father implements Filial, Spoony {

  @Override
  public void help() {
    System.out.println("我該就誰呢?");
    Filial.super.help();
    Spoony.super.help();
  }
  
}      

359 内部類的分類 

類的内部成員之五:内部類

1.java中允許将一個類A聲明在另一個類B中,則類A就是内部類,類B稱為外部類

2.内部類的分類:成員内部類(靜态和非靜态)vs局部内部類(方法内,代碼塊内,構造器内)

3.成員内部類:

       一方面,作為外部類的成員:

      >調用外部類的結構

       >可以被static修飾

       >可以被四種不同的權限修飾

       另一方面,作為一個類:

       >類内可以定義屬性,方法,構造器等

       >可以被final修飾,表示此類不能被繼承,言外之意,不使用final,就可以被繼承

       >可以被abstract修飾

public class InnerClassTest{
   public static void main(String[] args){
     //建立Dog執行個體(靜态的成員内部類)
     Person.Dog dog=new Person.Dog();
     dog.show();
     //建立Bird執行個體(非靜态的成員内部類)
     Person p=new Person();
     Person.Bird bird=p.new Bird();
     bird.sing();
     System.out.println();
     bird.display("黃鹂");
   }
}
class Person{
   String name="小明";
   int age;
   public void eat(){
      System.out.println("人,吃飯");
   }
   //靜态成員内部類
   static class Dog{
       String name;
       int age;
       public void show(){
         System.out.println("卡拉是條狗");
         //eat();
       }
   }
   //非靜态成員内部類
   class Bird{
        String name="杜鵑";
        public Bird(){
        }
        public void sing(){
            System.out.println("我是一隻小小鳥");
            Person.this.eat();//調用外部類的非靜态屬性
        }
        public void display(String name){
             System.out.println(name);//方法的形參
             System.out.println(this.name);//内部類的屬性
             System.out.println(Person.this.name);//外部類的屬性
             
        }
   }
   public void method(){
      //局部内部類
      class AA{
      }
   }
   {
      //局部内部類
      class BB{
      
      }
   }
   public Person(){
        //局部内部類
        class CC{
        }
   }
}      

361 如何執行個體化成員内部類

 4.關注如下的三個問題

  4.1如何執行個體化成員内部類的對象

  4.2 如何在成員内部類中去區分調用外部類的結構

  4.3 開發當中,局部内部類的使用

public class InnerClassTest1{
    //開發中很少見
    public void method(){
        //局部内部類
        class AA{
        }
    }
    //傳回一個實作了Comparable接口的類的對象
    public Comparable getComparable(){
        //建立一個實作了Comparable接口的類:局部内部類
        //方式一:
          class MyComparable implements Comparable{
                public int compareTo(Object o){
                      return 0;
                }
          }
          return new MyComparable();
          //方式二:
          return new Comparable(){
              public int compareTo(Object o){
                 return 0;
              }
          };
     }
}      

368 異常處理 局部内部類使用的一個注意點 

在局部内部類的方法中,比如show,如果調用局部内部類所聲明的方法(比如:method)中的局部變量(比如number)的話,要求此局部變量聲明為final的

jdk7及之前版本,要求此局部變量顯式的聲明為final的

jdk8及之後的版本,可以省略final的聲明

public class InnerClassTest{
    public void method(){
        //局部變量
        final int num=10;
        class AA{
           public void show(){
              //num=20;
              System.out.println(num);      

369 異常處理 異常概述

01、異常概述與異常體系結構

在使用計算機語言進行項目開發的過程中,即使程式員把代碼寫得盡善盡美,在系統的運作過程中仍然會遇到一些問題,因為很多問題不是靠代碼能夠避免的,比如:客戶輸入資料的格式,讀取檔案是否存在,網絡是否始終保持通暢等等。

異常:

在Java語言中,将程式執行中發生的不正常情況稱為“異常”。(開發過程中的文法錯誤和邏輯錯誤不是異常)

Java程式在執行過程中所發生的異常事件可分為兩類:

Error:Java虛拟機無法解決的嚴重問題。如:JVM系統内部錯誤、資源耗盡等嚴重情況。比如:StackOverflowError和OOM。一般不編寫針對性的代碼進行處理。

public class ErrorTest{
   public static void main(String[] args){
        //1.棧溢出:java.lang.StackOverflowError
        //main(args);
        //2.堆溢出:java.lang.OutOfMemoryError
        Integer[] arr=new Interger[1024*1024*1024];
  }
}      
  • Exception:其它因程式設計錯誤或偶然的外在因素導緻的一般性問題,可以使用針對性的代碼進行處理。例如:
  • 空指針通路
  • 試圖讀取不存在的檔案
  • 網絡連接配接中斷
  • 數組角标越界

 370 異常的分類

對于這些錯誤,一般有兩種解決方法:

一是遇到錯誤就終止程式的運作。

另一種方法是由程式員在編寫程式時,就考慮到錯誤的檢測、錯誤消息的提示,以及錯誤的處理。

捕獲錯誤最理想的是在編譯期間,但有的錯誤隻有在運作時才會發生。比如:除數為0,數組下标越界等

異常分類:編譯時異常和運作時異常

一,異常體系結構

java.lang.Throwable

                ------java.lang.Error:一般不編寫針對性的代碼進行處理

                ------java.lang.Exception:可以進行異常的處理

                      -------編譯時異常(checked)

                               -----IOExpection

                                    ------FileNotFoundExpection

                              -----ClassNotFoundExpection

                    --------運作時異常(unchecked)

                               ------NullPointerExpection

                               ------ArrayIndexOutOfBoundsException

                               ------ClassCastExpection

                               ------NumberFormatException

                               ------InputMismatchException

                               ------ArithmeticException

面試題:常見的異常有哪些?舉例說明

371 常見異常的舉例

public class ExceptionTest{
    //以下是運作時異常
    //NullPointerException
    public void test1(){
//        int[] arr=null;
//        System.out.println(arr[3]);
          String str="abc";
          str=null;
          System.out.println(str.charAt(0));
    }
    //IndexOutOfBoundsException
    public void test2{
        //ArrayIndexOutOfBoundsException
        int[] arr=new int[10];
        System.out.println(arr[10]);
        //StringIndexOutOfBoundsException
        String str="abc";
        System.out.println(str.charAt(3));
    }
    //ClassCastException
    public void test3(){
          Object obj=new Date();
          String str=(String)obj;
    }
    //NumberFormatException
    public void test4(){
        String str="123";
        str="abc";
        int num=Integer.parseInt(str);
    }
    //InputMismatchException
    public void test5(){
        Scanner scanner=new Scanner(System.in);
        int score=scanner.nextInt();
        System.out.prinln(score);
        scanner.close();
    }
    //ArithmeticException
    public void test6(){
          int a=10;
          int b=0;
          System.out.println(a/b);
    }
    //以下是編譯時異常
    public void test7(){
          File file=new File("hello.txt");
          FileInputStream fis=new FileInputStream(file);
          int data=fis.read();
          while(data!=-1){
             System.out.println((char)data);
             data=fis.read();
          }
          fis.close();
    }      

372 異常處理方式概述 

在編寫程式時,經常要在可能出現錯誤的地方加上檢測的代碼,如進行x/y運算時,要檢測分母為0,資料為空,輸入的不是資料而是字元等。過多的if-else分支會導緻程式的代碼加長、臃腫,可讀性差。是以采用異常處理機制。

Java采用的異常處理機制,是将異常處理的程式代碼集中在一起,與正常的程式代碼分開,使得程式簡潔、優雅,并易于維護。

方式一:try-catch-finally

方式二:throws + 異常類型

異常的處理:抓抛模型

過程一:抛:程式在正常執行的過程中,一旦出現異常,就會在異常代碼處生成對應異常類的對象

并将此對象抛出,一旦抛出對象以後,其後的代碼不再執行

過程二:抓:可以了解為異常的處理方式

1.try-catch-finally

2.throws

373 處理異常 try-catch方式

try{

     //可能出現異常的代碼

}catch(異常類型1 變量名1){

    //處理異常的方式1

}catch(異常類型2 變量名2){

    //處理異常的方式2

}catch(異常類型3 變量名3){

    //處理異常的方式3

}

.....

finally{

     //一定會執行的代碼

}

public class ExpectionTest1{
  public void test1(){
      String str="123";
      str="abc";
      try{
          int num=Integer.parseInt(str);
          System.out.println("hello----1");
      }catch(NumberFormatExpection e){
         // System.out.println("出現數值轉換異常了,不要着急");
         //String getMessage():
         System.out.println(e.getMessage());
         //printStackTrace():
         e.printStackTrace();
      }
      System.out.println("hello----2");
}      

說明:

1.finally是可選的

2.使用try将可能出現異常代碼包裝起來,在執行過程中,一旦出現異常,就會生成一個對應異常類的對象,根據此對象的類型,去catch中進行比對

3.一旦try中的異常對象比對到某一個catch中,就進入catch中進行異常的處理,一旦處理完成,就跳出目前的try-catch結構(在沒有寫finally結構的情況下)繼續執行其後的代碼

4.catch中的異常類型如果沒有子父類關系,則誰聲明在上,誰聲明在下無所謂

 catch中的異常類型如果滿足子父類關系,則要求子類一定聲明在父類的上面,否則,報錯

5.常用的異常處理的方式

   1.String getMessage()

   2.printStackTrace()

6.在try結構中聲明的變量,再出了try結構以後,就不能再被調用

7.結構可以嵌套

體會1:使用處理編譯時異常,使得程式在編譯時就不再報錯,但是運作時仍可能報錯,相當于我們使用将一個編譯時可能出現的異常,延遲到運作時出現

體會2:開發中,由于運作時異常比較常見,是以我們通常不針對運作時異常編寫try-catch-finally

針對于編譯時異常,我們說一定要考慮異常的處理

374 finally的使用

1.finally是可選的

2.finally中聲明的是一定會被執行的代碼,即使catch中又出現異常了,try中有return語句,catch中有return語句等情況

3.像資料庫連接配接,輸入輸出流,網絡程式設計Socket等資源,JVM是不能被自動的回收的,我們需要自己手動的進行資源的釋放,此時的資源釋放,就需要聲明在finally中

public class FinallyTest{
    @Test
    public void test2() {
        FileInputStream fis = null;
        try {
            File file = new File("hello1.txt");//檔案可能不存在,而出現異常
            fis = new FileInputStream(file);

            int data = fis.read();
            while (data != -1) {
                System.out.print((char) data);
                data = fis.read();
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null)
                    fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void testMethod(){
         int num=method();
         System.out.println(num);
    }
    public int method(){
         try{
             int[] arr=new int[10];
             System.out.println(arr[10]);
             return 1;
           }catch(ArrayIndexOutOfBoundsException e){
              e.printStackTrace();
              return 2;
          }finally{
              System.out.println("我一定會被執行");
          }
    public void test1(){
       try{
           int a=10;
           int b=0;
           System.out.println(a/b);
          }catch(ArithmetricException e{
             e.printStackTrace();
          }
          finally{
            System.out.println("我好帥啊");
          }
    }
}      

376 throws方式 

異常處理的方式二:throws+異常類型

1.throws+異常類型 寫在方法的聲明處,指明此方法執行時,可能會抛出的異常類型,一旦當方法體執行時,出現異常,仍會在異常代碼處生成一個異常類的對象,此對象滿足throws後異常類型時,就會被抛出。異常代碼後續的代碼不再執行

2.異常處理有兩種方式

第一種:真正的異常被處理掉了、

第二種:隻是将異常抛給了方法的調用者,并沒有真正将異常處理掉

public class ExceptionTest2{
        public static void main(String[] args){
             try{
                method2();
               }catch(IOException e){
                  e.printStackTrace();
               }
               method3();
        }
        public static void method3(){
             try{
                 method2();
              }catch(IOException e){
                 e.printStackTrace();
              }
        }
        public void method2() throws IOException{
            method1();
        }
        public static void method1() throws FileNotFoundException,IOException{
    File file = new File("hello1.txt");
    FileInputStream fis = new FileInputStream(file);
    
    int data = fis.read();
    while(data != -1){
      System.out.print((char)data);
      data = fis.read();
    }
    
    fis.close();
    
    System.out.println("hahaha!");
  }
}      

377 重寫方法異常抛出的規則

方法重寫的規則之一:

子類重寫的方法抛出的異常類型不大于父類被重寫的方法抛出的異常類型

public class OverrideTest{
   public static void main(String[] args){
        OverrideTest test=new OverrideTest();
        test.display(new SubClass());
   }
   public void display(SuperClass s){
      try{
          s.method();
      }catch(IOException e){
           e.printStackTrace();
      }
   }
}
class SuperClass{
     public void method() throws IOException{
     }
}
class SubClass extends SuperClass{
     public void method() throws FileNotFoundException{
     }
}      

378 開發中如何選擇哪種方式處理異常 

1.如果父類中被重寫的方法沒有throws方式處理異常,則子類重寫的方法也不能使用throws,意味着如果子類重寫的方法中有異常,必須使用try-catch-finally方式處理

2.執行的方法中,先後又調用了另外的幾個方法,這幾個方法是遞進關系執行的,我們建議這幾個方法使用throw的方式進行處理,而執行的方式a可以考慮使用try-catch-finally方式進行處理。

379 手動抛出異常對象

public class StudentTest{
   public static void main(String[] args){
     try{
     Student s=new Student();
     s.regist(1001);
     System.out.println(s);
     }catch(Exception e){
        //e.printStackTrace();
        System.out.println(e.getMessage());
     }
   }
}
class Student{
   private int id;
   public void regist(int id){
        if(id>0){
            this.id=id;
        }else{
           //System.out.println("您輸入的資料非法");
           //手動抛出異常對象
           //throw new RuntimeException("您輸入的資料非法");
           throw new Exception("您輸入的資料非法");
           
        }
  }
  public String toString(){
     return "Student [id="+id+"]";
  }
}