Java基礎10-接口,抽象類以及異常

一.接口
 1.什麼是接口
  接口是特殊的抽象類,其內部方法都是抽象的
 
 2.接口與抽象類的區別:
  a.接口是interface;抽象類是abstract class
  b.接口的方法都是抽象的;抽象類的方法可以不是抽象的
  c.接口的成員有默認修飾符:方法是public abstract,變量是public static final;抽象類沒有默認修飾符
  d.接口的實現使用implements關鍵字;抽象類的繼承使用extends關鍵字
  e.接口可以被多實現;抽象類只能被單繼承
  
 
3.什麼時候使用抽象類和接口?
  a.當存在繼承關係時使用抽象類;沒有繼承關係時就使用接口
  b.當方法都是抽象時使用接口;若既有抽象方法,又有實例方法時,使用抽象類
  
 
注:
  接口與接口,使用extends關鍵字;
  實現接口後,子類方法必須爲public;
  
 
4.面試題一:
  一個類可以實現兩個接口嗎?任意兩個接口都可以嗎?
  
  答: 可以.不可以.
   因爲若是兩個接口的方法名相同,參數列表相同,但其返回值類型不同,此時子類就不能同時實現這兩個接口了.
   如:
    interface A {
     int fun();
    }
    interface B {
     void fun();
    }
 
 5.面試題二:
  什麼情況下,會將子類類型強轉爲父類類型呢?
  
  答:當一個子類對象能夠匹配多個重載方法而且方法的形參都是該子類實現的父類類型們.
  這時會出現調用不明確的情況,所以需要進行強轉爲父類類型.
  如:
   interface Teacher {
    void teach();
   }
   interface Coder {
    void code();
   }
   
   class Person implements Teacher,Coder {
    public static void main(String[] args) {
     Person p = new Person();
     p.work( (Teacher)p );  //強轉類型轉換
     p.work( (Coder)p );    //強轉類型轉換
    }
    
    @Override
    public void teach(){ }
    
    @Override
    public void code(){ }
    
    public static void work(Teacher t) {
     t.teach();
    }
    
    public static void work(Coder c) {
     c.code();
    }
   }
   
二.策略設計模式-StrategyPattern
 使用接口,降低耦合性
 
 如:
  class TestDemo {
   public static void main(String[] args) {
    int[] arr={1,4,6,7,3,5,9,-6,-34,67,-12};
    Printer.print(arr);
    
    //需求: 要打印其中的正數 (此時就可以使用策略設計,添加過濾器,使用接口來實現)
    
    Printer.print(arr, new Filter(){  //add: 使用匿名內部類
     @Override
     public boolean accept() {
      return i >= 0;
     }  
    });
    
   } 
  }
  
  class Printer {
   public static void print(int[] arr) {
    for(int i=0;i<arr.length;i++)
     System.out.print(arr[i]+" ");
    System.out.println();
   }
   
   public static void print(int[] arr,Filter f) {       //add
    for(int i=0;i<arr.length;i++)
     if(f.accept(arr[i]))                         //add
      System.out.print(arr[i]+" ");
    System.out.println();
   }
  }
  
  interface Filter {
   boolean accept(int i);
  }
  
  
三.內部類: ( 內部類可以訪問外部類成員 )
 
類中:
  成員內部類
  靜態內部類
 
方法中: 
  局部內部類
  匿名內部類
 
 
1.什麼是內部類
  在內部類中定義的類,就是內部類
  
 2.成員內部類: ( A$B.class )
 
 a.什麼是成員內部類
   定義在類的成員位置的內部類,就是成員內部類
   創建該內部類的對象,必須先創建外部類對象,才能通過外部類對象創建內部類對象;
  注:
   創建格式爲: 外部類名.內部類名 變量名= new 外部類名().new 內部類名();
   一個外部類可以創建多個內部類對象,但一個內部類對象只能對應一個外部類對象;
   
  b.什麼時候使用成員內部類?
   當一個類想要訪問另一個類的成員時
  
  
c.內部類訪問外部類的成員的方式:
   使用: 外部類名.this.成員名 


  注:
   在方法中,"this" 代表當前方法的對象,而"外部類.this" 代表當前方法的對象的外部類對象
   外部類不能訪問內部類成員
   
  
d.內部類中不能定義靜態成員
   因爲內部類必須依賴外部類對象才能創建對象,而static是指不需創建對象就可以使用
   
 
3.局部內部類: ( A$1B.class )
 
 a.什麼是局部內部類
   定義在方法中的內部類,就是局部內部類
   
  b.局部內部類與成員內部類的區別:
   局部內部類,只能在方法中使用;成員內部類可以在外面使用
   創建局部內部類的代碼在方法中,而且必須寫在類定義的後面;
      
  
c.方法中的內部類怎麼創建對象
   在方法中直接使用 new 類名()即可
   
  d.方法中的內部類怎麼訪問方法中的局部變量
   局部內部類訪問方法的局部變量時,該局部變量必須使用final修飾;  
   
  如:
   class TestDemo {
    public static void main(String[] args) {
     new A().fun();
    } 
   }
   
   class A {
   
    class B {
     B() {
      System.out.println("成員內部類B..");
     }
    }
    
    void fun() {
    
     class B {
      B() {
       System.out.println("局部內部類B..");
      }
     }
     
     /*
     B b = new B(); 
//1.這邊創建B對象是根據從內到外的優先級進行選擇的,只有當內部不存在就會向外尋找
     */
     
     //需求: 當前代碼下,
     //創建成員內部類B的對象:
A.B b2 = new A.B();
     //創建外類B的對象的方法:
包名.B b3 = new 包名.B();
     
    }
   }
   
   class B {
    B() {
     System.out.println("外部類B..");
    }
   }
   
   
 
4.匿名內部類 ( A$1.class )
 格式:
  new 父類名(){
   //重寫方法
  }


  a.什麼是匿名內部類
   沒有名字的局部內部類,就是匿名內部類
  
  b.什麼時候使用匿名內部類
   局部內部類只需使用一次,使用匿名內部類可以簡化書寫
 
  c.匿名內部類的class文件名
   A$1.class
   
 5.靜態內部類
  a.什麼是靜態內部類
   使用static修飾的內部類
   
  b.靜態內部類和普通的類中內部類的區別
   創建對象: 靜態內部類不需創建外部類對象,就可以直接建立內部內部類 ( 外部類名.內部類名 變量名 = new 外部類名.內部類名(); )
       成員內部類需要通過創建外部類對象來創建自己的對象 ( 外部類名.內部類名 變量名 = new 外部類名().new 內部類名(); )
   訪問外部成員: 靜態內部類只能訪問外部類的靜態成員,而不能訪問非靜態成員
   定義靜態成員: 靜態內部類可以定義靜態成員;而成員內部類是不可以定義靜態成員( 靜態變量/方法/代碼塊 ),可以定義靜態常量
   


三.異常
 
 Throwable
 --Error
    --
 --Exception
    --RuntimeException
    --
  
 1.什麼是異常
  異常就是程序運行過程中出現的一些錯誤, 使用throw關鍵字拋出的一些對象.
  可以通知調用處, 調用處下面的代碼不會再執行了.
  
 2.異常的處理方式
 
 a.聲明
   若是沒有處理,則需要在方法上(參數列表後面)使用"throws 異常名"進行聲明,將異常繼續向上拋出
  
  b.捕捉
   try {
   
   }catch(異常名 變量名) {
    //處理代碼
   }
  
 3.異常的分類
 
 a.編譯時異常
   Exception中除了RuntimeException的部分, 編譯之前在代碼中必須對其進行聲明或捕捉, 否則編譯報錯
   
  b.運行時異常
   RuntimeException或其子類, 在代碼中可以不對其進行處理, 編譯不報錯.
   這類異常經常會出現, 例如數組索引越界, 空指針, 算數異常, 如果對其進行處理, 非常麻煩, 代碼可讀性也會下降.
   
 4.多個異常的處理方式
  a.聲明
   在方法上使用"throws 異常1名,異常2名"進行聲明
  
 
 b.捕捉
   try {
   
   }catch(異常1名 變量名) {
    //處理代碼
   }catch(異常2名 變量名) {
    //處理代碼
   }


  注:
   異常捕捉的書寫順序: 子類異常放在前面
  
 5.子類重寫父類方法時注意的異常問題
  重寫的條件之一: 子類的方法只能拋出父類方法異常的子集,不能拋出比父類更多的異常
 如:
  class A {
   void fun() throws Exception {
   
   }
  }
  
  class B {
   @Override
   public void fun() throws FileNotFoundException { //可以不拋,也可以拋出相同的異常,也可以拋出父類異常的子類!!!!
   
   }
  }
  
 6.finally的使用
  finally是配合try使用的, 只要執行了try中的代碼, finally中的代碼就一定會執行. (一些特殊情況除外:如System.exit(0); )
 
 注:
  class TestDemo {
   public static void main(String[] args) throws Exception {   
    /*
    打印結果一:(System.out,println(10/1);)
     10
     異常處理之前
     finally語句
     
    打印結果二:(System.out,println(10/0);)
     異常處理
     finally語句
    */
    try {
     System.out.println(10/1);           //
     System.out.println("異常處理之前");
     return ;
    }catch(Exception e) {
     System.out.println("異常處理..");
    
    }finally {    
     System.out.println("finally語句");
    }
   } 
  }
  
  
補充:
 猴子分桃問題
 注:
  class TestDemo {
   public static void main(String[] args) {   
    
    outer:
     for(int i=0;i<9999;i++) {
      int count=i; 
      for(int j=0;j<5;j++){
       if( (count-1)%5==0 )
        count = (count-1)/5*4;
       else
        continue outer;
      }  
      System.out.println(i);       
     }
    
   } 
   
  }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章