天天看點

接口-多态-内部類(匿名内部類)1.接口2.多态3.内部類4.引用類型使用小結

1.接口

概述: 接口是Java語言中的一種引用類型,是方法的"集合",是以接口的内部主要就是定義方法,包含常量,抽象方法(JDK 7及以前),預設方法和靜态方法(JDK 8),私有方法(jdk9)。
  • 抽象方法【重要】
  • 預設方法
  • 靜态方法
  • 私有方法
  • 自定義常量

接口的定義,它與定義類方式相似,但是使用

interface

關鍵字。它也會被編譯成.class檔案,但一定要明确它并不是類,而是另外一種引用資料類型。

public class 類名.java–>.class

public interface 接口名.java–>.class

引用資料類型:數組,類,接口。

接口的使用,它不能建立對象,但是可以被實作(

implements

,類似于被繼承)。一個實作接口的類(可以看做是接口的子類),需要實作接口中所有的抽象方法,建立該類對象,就可以調用方法了,否則它必須是一個抽象類。

小結:

  • 接口是Java語言中的一種引用類型,
  • 接口中主要用來定義方法的:
    • jdk7及其以前: 常量,抽象方法
    • jdk8: 額外增加預設方法和靜态方法
    • jdk9及其以上: 額外增加了私有方法
  • 定義接口使用interface關鍵字, 編譯之後也會産生class檔案
  • 接口不能建立對象, 需要實作接口(implements), 實作接口的類叫做實作類(接口的子類)
    • 實作類: 普通類 必須重寫接口中的抽象方法
    • 實作類 ;抽象類 可以不用重寫接口中的抽象方法

定義格式

格式

public interface 接口名稱 {
    // 常量
    // 抽象方法
    // 預設方法
    // 靜态方法
}
           

案例

public interface IA {
    // 常量 預設修飾符 public static final  這三個修飾符可以省略
    public static final int NUM1 = 10;
    int NUM2 = 20;

    // 抽象方法 預設修飾符 public abstract 這2個修飾符可以省略
    public abstract void method1();
    void method2();

    // 預設方法 預設修飾符 public default public修飾符可以省略,default不可以省略
    public default void method3(){
        System.out.println("預設方法 method3");
    }

    default void method4(){
        System.out.println("預設方法 method4");
    }

    // 靜态方法: public static修飾  static修飾符不可以省略 public可以省略
    public static void method5(){
        System.out.println("靜态方法 method5");
    }

     // 私有靜态方法 使用private static修飾  不可以省略
     private static void method6(){
        System.out.println("私有靜态方法 method6");
    }

    // 私有非靜态方法 使用private修飾
    private  void method7(){
        System.out.println("私有靜态方法 method7");
    }
}

public class Test {
    public static void main(String[] args) {
        /*
            接口的定義:
                public interface 接口名{
                     jdk7及其以前:  常量,抽象方法
                     jdk8: 額外增加預設方法和靜态方法
                     jdk9及其以上: 額外增加了私有方法
                }
         */
        System.out.println(IA.NUM1);// 10
    }

    // 類中的預設方法,使用預設權限修飾符(空)
    void method(){

    }
}

           
實作概述

類與接口的關系為實作關系,即類實作接口,該類可以稱為接口的實作類,也可以稱為接口的子類。實作的動作類似繼承,格式相仿,隻是關鍵字不同,實作使用

implements

關鍵字。

實作格式
  • 類可以實作一個接口,也可以同時實作多個接口。
    • 類實作接口後,必須重寫接口中所有的抽象方法,否則該類必須是一個“抽象類”。
      public interface IA{
          public void show1();
      }
      public interface IB{
          public void show2();
      }
      public class Zi implements IA ,IB{
          public void show1(){
          }
          public void show2(){
          }
      }
                 
  • 類可以在“繼承一個類”的同時,實作一個、多個接口;
    public class Fu{}
    public interface IA{}
    public interface IB{}
    public class Zi extends Fu implements IA,IB{//一定要先繼承,後實作
    }
    
               

接口中成員的通路特點

接口中成員的通路特點:
                接口中的常量: 主要是供接口直接使用
                接口中的抽象方法: 供實作類重寫的
                接口中的預設方法: 供實作類繼承的(實作類中可以直接調用,實作類對象也可以直接調用)
                接口中的靜态方法: 隻供接口直接調用,實作類繼承不了
                接口中的私有方法: 隻能在接口中直接調用,實作類繼承不了
           
案例示範
接口

/**
 * @Author:pengzhilin
 * @Date: 2020/4/16 11:57
 */
public interface IA {
    //  接口中的常量: 主要是供接口直接使用
    public static final int NUM = 10;

    // 接口中的抽象方法: 供實作類重寫的
    public abstract void method1();

    // 接口中的預設方法: 供實作類繼承使用(實作類中可以直接調用,實作類對象也可以直接調用)
    public default void method2(){
        System.out.println("預設方法method2");
        method4();
        method5();
    }

    // 接口中的靜态方法: 隻供接口直接調用,實作類繼承不了
    public static void method3(){
        System.out.println("靜态方法method3");
        method5();
    }

    // 接口中的私有方法: 隻能在接口中直接調用,實作類繼承不了
    private void method4(){// 隻能在接口的預設方法中調用
        // 方法體
        method5();
    }

    private static void method5(){//
        // 方法體
    }
}

實作類:

/**
 * @Author:pengzhilin
 * @Date: 2020/4/16 11:59
 */
public class ImpA implements IA{

   /* @Override
    public void method2() {

    }*/

    @Override
    public void method1() {
        System.out.println("重寫接口中的method1抽象方法");
    }
}


測試類:

/**
 * @Author:pengzhilin
 * @Date: 2020/4/16 11:54
 */
public class Test {
    public static void main(String[] args) {
        /*
            接口中成員的通路特點:
                接口中的常量: 主要是供接口直接使用
                接口中的抽象方法: 供實作類重寫的
                接口中的預設方法: 供實作類繼承的(實作類中可以直接調用,實作類對象也可以直接調用)
                接口中的靜态方法: 隻供接口直接調用,實作類繼承不了
                接口中的私有方法: 隻能在接口中直接調用,實作類繼承不了
         */
        System.out.println(IA.NUM);// 10

        // 建立實作類對象,通路NUM常量
        ImpA ia = new ImpA();
        System.out.println(ia.NUM);// 10

        // 調用method2方法
        ia.method2();

        // 通過接口名調用接口中的靜态方法
        IA.method3();
        //ia.method3();// 編譯報錯,
    }
}

           

多實作時的幾種沖突情況

公有靜态常量的沖突
了解即可, 一般會使用靜态所在類的類名去調用
  • 實作類不繼承沖突的變量
interface IA{
    public static final int a = 10;
    public static final int b= 20;
}
interface IB{
    public static final int a = 30;
}
class Zi implements IA,IB{
    //隻繼承了b,沒有繼承a,因為a沖突了
}

public class Demo {
    public static void main(String[] args) {
        Zi z = new Zi();
     //   System.out.println(z.a);//編譯錯誤
        System.out.println(z.b);
    }
}

           
公有抽象方法的沖突
  • 實作類==隻需要重寫一個 ==
interface IA{
    public void show();
}
interface IB{
    public void show();
}
class Zi implements IA,IB{
    @Override
    public void show() {//子類隻需要重寫一個show()即可
        System.out.println("子類的show()...");
    }
}
public class Demo {
    public static void main(String[] args) {
        Zi z = new Zi();
        z.show();
    }
}
           
公有預設方法的沖突
  • 實作類必須重寫一次最終版本
interface IA{
    public default void show(){
        System.out.println("IA");
    }
}
interface IB{
    public default void show(){
        System.out.println("IB");
    }
}
class Zi implements IA,IB{
    @Override
    public void show() {//必須重寫一次的show()
        System.out.println("Zi的show()....");
    }
}
public class Demo {
    public static void main(String[] args) {
        Zi z = new Zi();
        z.show();
    }
}


           
公有靜态方法的沖突
  • 靜态方法是直接屬于接口的,不能被繼承,是以不存在沖突
    interface IA{
        public static  void show(){
            System.out.println("IA");
        }
    }
    interface IB{
        public static void show(){
            System.out.println("IB");
        }
    }
    class Zi implements IA,IB{
    
    }
    public class Demo {
        public static void main(String[] args) {
            Zi z = new Zi();
            z.show();//編譯錯誤,show()不能被繼承。
        }
    }
    
    
    
               
私有方法的沖突
  • 私有方法隻能在本接口中直接使用,不存在沖突

接口和接口的關系

  • 接口可以“繼承”自另一個“接口”,而且可以“多繼承”。
    interface IA{}
    interface IB{}
    interface IC extends IA,IB{//是“繼承”,而且可以“多繼承”
    }
    
               
接口繼承接口的沖突情況

公有靜态常量的沖突

interface IA{
    public static final int a = 10;
    public static final int b = 30;
}
interface IB{
    public static final int a = 20;
}
interface IC extends IA,IB{//沒有繼承a
}
//測試:
main(){
    System.out.println(IC.a);//錯誤的
}

           

公有抽象方法沖突

interface IA{
    public void show();
}
interface IB{
    public void show();
}
interface IC extends IA,IB{//IC隻繼承了一個show()
}
class Zi implements IC{
    //重寫一次show()
    public void show(){
    }
}

           

公有預設方法的沖突

interface IA{
    public default void d1(){
    }
}
interface IB{
    public default void d1(){
    }
}
interface IC extends IA,IB{//必須重寫一次d1()
    public default  void d1(){
    }
}

           

公有靜态方法和私有方法

  • 不沖突,因為靜态方法是直接屬于接口的,隻能使用接口直接通路,而私有方法隻能在接口中通路,也沒有沖突

抽象類和接口的練習

通過執行個體進行分析和代碼示範抽象類和接口的用法。

1、舉例:

​ 犬: 父類 ---->抽象類

​ 行為:吼叫;吃飯;

​ 緝毒犬: 繼承犬類

​ 行為:吼叫;吃飯;緝毒;

public abstract class Dog{
    // 吼叫   抽象方法 
    // 吃飯   抽象方法 
}

public interface JiDu{
    // 緝毒 抽象方法
}

public class JiDuDog extends Dog implements JiDu{
    // 重寫吼叫,吃飯方法
    // 實作緝毒的方法 ----  緝毒方式
}


緝毒豬,緝毒貓,緝毒候....

           
  • 如果一個父類中的某個方法,所有子類都有不同的實作,那麼該方法就應該定義成抽象方法,是以該父類就是抽象類 (父類一般都是抽象類)
  • 如果某個功能是一個類額外增加的,那麼就可以把這個額外的功能定義到接口中,再這個類去實作

分析:

​ 由于犬分為很多種類,他們吼叫和吃飯的方式不一樣,在描述的時候不能具體化,也就是吼叫和吃飯的行為不能明确。當描述行為時,行為的具體動作不能明确,這時,可以将這個行為寫為抽象行為,那麼這個類也就是抽象類。

​ 可是有的犬還有其他額外功能,而這個功能并不在這個事物的體系中 , 例如 : 緝毒犬。緝毒的這個功能有好多種動物都有 , 例如 : 緝毒豬 , 緝毒鼠。我們可以将這個額外功能定義接口中 ,讓緝毒犬繼承犬且實作緝毒接口 , 這樣緝毒犬既具備犬科自身特點也有緝毒功能。

  • 額外的功能—> 在接口中定義,讓實作類實作
  • 共性的功能—> 在父類中定義,讓子類繼承

實作:

//定義緝毒接口 緝毒的詞組(anti-Narcotics)比較長,在此使用拼音替代
interface JiDu{
    //緝毒
	public abstract void jiDu();
}
//定義犬科,存放共性功能
abstract class Dog{
    //吃飯
	public abstract void eat();
    //吼叫
	public abstract void roar();
}
//緝毒犬屬于犬科一種,讓其繼承犬科,擷取的犬科的特性,
//由于緝毒犬具有緝毒功能,那麼它隻要實作緝毒接口即可,這樣即保證緝毒犬具備犬科的特性,也擁有了緝毒的功能
class JiDuQuan extends Dog implements JiDu{
	public void jiDu() {
	}
	void eat() {
	}
	void roar() {
	}
}

//緝毒豬
class JiDuZhu implements JiDu{
	public void jiDu() {
	}
}

           

小結:

  • 額外的功能—> 在接口中定義,讓實作類實作
    • 如果可以确定的通用功能,使用預設方法
    • 如果不能确定的功能,使用抽象方法
  • 共性的功能—> 在父類中定義,讓子類繼承
    • 如果可以确定的通用功能,使用預設方法
    • 如果不能确定的功能,使用抽象方法

2.多态

多态是繼封裝、繼承之後,面向對象的第三大特性。

生活中,比如跑的動作,小貓、小狗和大象,跑起來是不一樣的。再比如飛的動作,昆蟲、鳥類和飛機,飛起來也是不一樣的。可見,同一行為,通過不同的事物,可以展現出來的不同的形态。多态,描述的就是這樣的狀态。

定義

  • 多态: 是指同一行為,對于不同的對象具有多個不同表現形式。
  • 同一種事物的多種形态
  • 程式中多态: 是指同一方法,對于不同的對象具有不同的實作.

前提條件【重點】

  1. 繼承或者實作【二選一】
  2. 父類引用指向子類對象【格式展現】
  3. 方法的重寫【意義展現:不重寫,無意義】

小結:

  • 多态: 是指同一行為,對于不同的對象具有多個不同表現形式。
  • 條件:
    • 繼承或者實作
    • 父類引用指向子類的對象
    • 方法的重寫

多态的展現:父類的引用指向它的子類的對象:

父類類型 變量名 = new 子類對象;
變量名.方法名();

           
父類類型:指子類對象繼承的父類類型,或者實作的父接口類型。
class Animal{}
class Cat extends Animal{}
class Dog extends Animal{}
clsss Person{}
//測試類:
main(){
    Animal a1 = new Cat();
    Animal a2 = new Dog();
    Animal a3 = new Person();//編譯錯誤,沒有繼承關系。
}


           

多态時通路成員的特點

  • 多态時成員變量的通路特點
    • 編譯看左邊,運作看左邊
      • 簡而言之:多态的情況下,通路的是父類的成員變量
  • 多态時成員方法的通路特點
    • 非靜态方法:編譯看左邊,運作看右邊
      • 簡而言之:編譯的時候去父類中查找方法,運作的時候去子類中查找方法來執行
    • 靜态方法:編譯看左邊,運作看左邊
      • 簡而言之:編譯的時候去父類中查找方法,運作的時候去父類中查找方法來執行
  • 注意:多态的情況下是無法通路子類獨有的方法
  • 示範代碼:
public class Demo1 {
    public static void main(String[] args) {
        // 父類的引用指向子類的對象
        Animal anl1 = new Dog();
        // 通路非靜态方法
        anl1.eat();

        // 通路成員變量num
        System.out.println(anl1.num);//10

        // 通路靜态方法
        anl1.sleep();

        // 多态想要調用子類中獨有的方法
        // anl1.lookHome(); 錯誤的,無法通路  多态的弊端:無法通路子類獨有的方法

    }
}

public class Animal {

    int num = 10;

    public void eat(){
        System.out.println("吃東西...");
    }

    public static void sleep(){
        System.out.println("Animal類中的睡覺方法...");
    }

}

public class Dog extends Animal {

    int num = 20;

   // 重寫
    public void eat() {
        System.out.println("狗吃骨頭");
    }

    public static void sleep(){
        System.out.println("Dog類中的睡覺方法...");
    }

    public void lookHome(){
        System.out.println("狗正在看家...");
    }

}


           

多态的幾種表現形式

  • 多态的表現形式:
    • 普通父類多态
      public class Fu{}
      public class Zi extends Fu{}
      public class Demo{
          public static void main(String[] args){
              Fu f = new Zi();//左邊是一個“父類”
          }
      }
      
      
                 
    • 抽象父類多态
      public abstract class Fu{}
      public class Zi extends Fu{}
      public class Demo{
          public static void main(String[] args){
              Fu f = new Zi();//左邊是一個“父類”
          }
      }
      
      
                 
    • 父接口多态
    public interface A{}
    public class AImp implements A{}
    public class Demo{
        public static void main(String[] args){
            A a = new AImp();
        }
    }
    
               

小結:

多态的應用場景:

  • 變量多态 -----> 意義不大
  • 形參多态----> 常用
  • 傳回值多态—> 常用

多态的幾種應用場景:

定義一個Animal類,讓Dog和Cat類繼承Animal類:
public class Animal {
    public void eat(){
        System.out.println("吃東西...");
    }
}
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("貓吃魚...");
    }
}

public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨頭...");
    }
}

public class Demo1 {
    public static void main(String[] args) {
        /*
            多态的應用場景:
                1.變量多态
                2.形參多态
                3.傳回值多态
         */
        // 1.變量多态
        Animal anl = new Dog();
        anl.eat();

        // 2.形參多态
        Dog dog = new Dog();
        invokeEat(dog);

        Cat cat = new Cat();
        invokeEat(cat);// 實參指派給形參: Animal anl = new Cat();

        // 3.傳回值多态
        Animal anl2 = getAnimal();// 傳回值指派給變量: Animal anl2 = new Dog()
    }

    //  3.傳回值多态
    // 結論:如果方法的傳回值類型為父類類型,那麼就可以傳回該父類對象以及其所有子類對象
    public static Animal getAnimal(){
//        return new Animal();
        return new Dog();
//        return new Cat();
    }

    // 形參多态: 當你調用invokeEat方法的時候,傳入Animal類的子類對象
    // Animal anl = dog; ====>  Animal anl = new Dog();
    // 結論:如果方法的參數是父類類型,那麼就可以接收所有該父類對象以及其所有子類對象
    // Object類:是java中所有類的父類,是以如果參數為Object類型,那麼就可以傳入一切類的對象
    public static void invokeEat(Animal anl){
        anl.eat();
    }

}

           

多态的好處和弊端

  • 實際開發的過程中,父類類型作為方法形式參數,傳遞子類對象給方法,進行方法的調用,更能展現出多态的擴充性與便利。但有好處也有弊端
  • 好處
    • 提高了代碼的擴充性
  • 弊端
    • 多态的情況下,隻能調用父類的共性内容,不能調用子類的特有内容。
  • 示例代碼
// 父類
public abstract class Animal {  
    public abstract void eat();  
}  
// 子類
class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃魚");  
    }  
    public void catchMouse(){
         System.out.println("貓抓老鼠");  
    }
}  
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨頭");  
    }  
}

           

定義測試類:

多态的好處:
public class Test {
    public static void main(String[] args) {
        // 建立對象
        Cat c = new Cat();  
        Dog d = new Dog(); 

        // 調用showCatEat 
        showCatEat(c);
        // 調用showDogEat 
        showDogEat(d); 

        /*
        以上兩個方法, 均可以被showAnimalEat(Animal a)方法所替代
        而執行效果一緻
        */
        showAnimalEat(c);
        showAnimalEat(d); 
    }

    public static void showCatEat (Cat c){
        c.eat(); 
    }

    public static void showDogEat (Dog d){
        d.eat();
    }

    public static void showAnimalEat (Animal a){
        a.eat();
    }
}

多态的弊端============
      public static void main(String[] args) {
        // 多态形式,建立對象
        Aniaml anl = new Cat();  
	    anl.eat();
    	anl.catchMouse();// 編譯報錯, 編譯看父類(左邊),父類中沒有定義catchMouse方法
    }

           

引用類型轉換

目标:

  • 向上轉型與向下轉型,instanceof關鍵字

步驟:

  • 向上轉型
  • 向下轉型
  • instanceof關鍵字

講解:

向上轉型
  • 子類類型向父類類型向上轉換的過程,這個過程是預設的。
向下轉型
  • 父類類型向子類類型向下轉換的過程,這個過程是強制的。
    Aniaml anl = new Cat();  
     Cat c = (Cat)anl;//向下轉型
     c.catchMouse();// 可以通路 子類獨有的功能,解決多态的弊端
    
    
               
instanceof關鍵字
  • 向下強轉有風險,最好在轉換前做一個驗證 :
  • 格式:
    變量名 instanceof 資料類型 
    如果變量屬于該資料類型,傳回true。
    如果變量不屬于該資料類型,傳回false。
    
    if( anl instanceof Cat){//判斷anl是否能轉換為Cat類型,如果可以傳回:true,否則傳回:false
        Cat c = (Cat)anl;//安全轉換
    }
    
               

3.内部類

将一個類A定義在另一個類B裡面,裡面的那個類A就稱為内部類,B則稱為外部類。

成員内部類

  • 成員内部類 :定義在類中方法外的類。

定義格式:

class 外部類 {
    class 内部類{

    }
}

           

在描述事物時,若一個事物内部還包含其他事物,就可以使用内部類這種結構。比如,汽車類

Car

中包含發動機類

Engine

,這時,

Engine

就可以使用内部類來描述,定義在成員位置。

代碼舉例:

class Car { //外部類
    class Engine { //内部類

    }
}

           

通路特點

  • 内部類可以直接通路外部類的成員,包括私有成員。
  • 外部類要通路内部類的成員,必須要建立内部類的對象。

建立内部類對象格式:

外部類名.内部類名 對象名 = new 外部類型().new 内部類型();

           

通路示範,代碼如下:

public class Body {// 外部類

    // 成員變量
    private int numW = 10;

    int num = 100;

    // 成員方法
    public void methodW1(){
        System.out.println("外部類中的methodW1方法...");
    }

    public void methodW2(){
        System.out.println("外部類中的methodW2方法...");
        // 建立内部類對象
        Body.Heart bh = new Body().new Heart();
        // 通路内部類成員變量
        System.out.println("内部類成員變量numN:"+bh.numN);
        // 通路内部類成員方法
        bh.methodN2();
    }

    public class Heart{// 成員内部類
        // 成員變量
        int numN = 20;

        int num = 200;

        // 成員方法
        public void methodN(){
            System.out.println("内部類中的methodN方法...");
            // 通路外部類成員變量
            System.out.println("外部類成員變量:"+numW);
            // 通路外部類成員方法
            methodW1();
        }

        public void methodN2(){
            System.out.println("内部類中的methodN2方法...");
        }

        public void methodN3(){
            int num = 300;
            System.out.println("局部變量num:"+num);// 300
            System.out.println("内部類成員變量num:"+this.num);// 200
            System.out.println("外部類成員變量num:"+Body.this.num);// 100
        }
    }
}
public class Demo {
    public static void main(String[] args) {
        // 測試
        // 建立外部類對象,調用外部類的方法methodW2
        Body body = new Body();
        body.methodW2();

        System.out.println("=======================");

        // 建立内部類對象,調用内部類的methodN方法
        Body.Heart heart = new Body().new Heart();
        heart.methodN();

        System.out.println("=======================");
        heart.methodN3();// 300  200  100
    }
}



           

小結:

内部類:将一個類A定義在另一個類B裡面,裡面的那個類A就稱為内部類,B則稱為外部類。
成員内部類的格式:
    public class 外部類名{
         public class 内部類名{

        }
    }
成員内部類的通路特點:
    - 内部類可以直接通路外部類的成員,包括私有成員。
    - 外部類要通路内部類的成員,必須要建立内部類的對象。

成員内部類的建立方式:
    外部類名.内部類名 對象名 = new 外部類名().new 内部類名();

           

成員内部類的建立方式:

外部類名.内部類名 對象名 = new 外部類名().new 内部類名();

知識點-- 匿名内部類

  • 匿名内部類 :是内部類的簡化寫法。它的本質是一個

    帶具體實作的

    父類或者父接口的

    匿名的

    子類對象。

代碼一

public abstract class Animal {
    public abstract void eat();
}
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨頭...");
    }
}
public class Test {
    public static void main(String[] args) {
        /*
            - 匿名内部類的概述:本質就是繼承了父類或者實作了接口的匿名子類的對象
            - 匿名内部類的格式:
                new 類名\接口名(){
                    方法重寫
                };

            - 匿名内部類的作用: 為了簡化代碼,并沒有什麼特殊的功能

            需求: 調用Aniaml類的eat()方法
            1.建立一個子類繼承Animal類
            2.在子類中重寫eat方法
            3.建立子類對象
            4.使用子類對象調用eat方法

            想要調用抽象類中的方法,必須具備以上4步,那能不能減後呢? 可以 使用匿名内部類
         */
        Animal anl1 = new Dog();
        anl1.eat();

        Animal anl2 = new Animal() {
            @Override
            public void eat() {
                System.out.println("Animal子類的eat方法...");
            }
        };
        anl2.eat();

    }
}

           

代碼二

public interface AInterface {
    void method();
}
public class AImp implements AInterface {
    @Override
    public void method() {
        System.out.println("AImp 實作類重寫method方法....");
    }
}
public class Demo {
    public static void main(String[] args) {
        /*
             匿名内部類:
                本質是一個繼承了父類的匿名子類的對象
                本質是一個實作了接口的匿名實作類的對象

              案例: A接口中有一個抽象方法method(),現在需要調用A接口中的method方法
              思路:
                1.建立一個實作類實作A接口
                2.重寫A接口中的抽象方法method()
                3.建立實作類對象
                4.使用實作類對象調用method方法

               想要調用A接口中的method方法,按照傳統方式,必須有以上4步,一步都不可少
               前面三步就是為了得到A接口的實作類對象

            現在: 匿名内部類可以表示一個接口的匿名實作類對象,是以,可以直接建立接口的匿名内部類來調用method方法即可
         */
        AInterface a = new AInterface(){
            @Override
            public void method() {
                System.out.println("匿名内部類方式重寫method方法....");
            }
        };
        a.method();

        System.out.println("==================");

        AInterface a2 = new AImp();
        a2.method();

        System.out.println("======================");
        AInterface a3 = new AInterface() {
            @Override
            public void method() {
                // 實作
            }
        };
    }
}

           

4.引用類型使用小結

實際的開發中,引用類型的使用非常重要,也是非常普遍的。我們可以在了解基本類型的使用方式基礎上,進一步去掌握引用類型的使用方式。基本類型可以作為成員變量、作為方法的參數、作為方法的傳回值,那麼當然引用類型也是可以的。在這我們使用兩個例子 , 來學習一下。
  • 類名作為方法參數和傳回值
    • 類名作為方法的參數: 調用方法傳入的是該類的對象
    • 類名作為方法的傳回值: 方法傳回的是該類的對象
  • 抽象類作為方法參數和傳回值
    • 抽象類作為方法的參數, 調用方法傳入的是該類的子類對象
    • 抽象類作為方法的傳回值: 方法傳回的是該類的子類對象
  • 接口作為方法參數和傳回值
  • 類作為成員變量
  • 抽象類作為成員變量 不常見
  • 接口作為成員變量 不常見

講解

6.1 類名作為方法參數和傳回值

public class Person{
  public void eat(){
    System.out.println("吃飯");
  }
}
public class Test{
  public static void main(String[] args){
        method(new Person());
   		Person p = createPerson();
  }
    
  //引用類型作為方法參數,在前面筆記本案例中我們也使用了接口類型作為方法參數
  pubic static void method(Person p){
       p.eat();
  }
    
  //引用類型作為傳回值
  public static Person createPerson(){
    	return new Person();
  }
}


           

6.2 抽象類作為方法參數和傳回值

  • 抽象類作為形參:表示可以接收任何此抽象類的"子類對象"作為實參;
  • 抽象類作為傳回值:表示"此方法可以傳回此抽象類的任何子類對象";
/* 定義一個抽象類 */
public abstract class Person{
    public void eat(){
        System.out.println("吃飯");
    }
    public abstract void work();
}
/*定義子類Student*/
public class Student extends Person{
    public void work(){
        System.out.println("學生的工作是學習...");
    }
}
/*測試類*/
public class Test{
     public static void main(String[] args) {
        //調用方法
        //當抽象類作為參數時,實際傳入的是抽象類的子類對象
        method(new Student());
    }

    public static void method(Person p){
    }

    //用抽象類作為方法傳回值類型
    public static Person method2(){
        
        //當抽象類作為傳回值類型時,實際傳回的是抽象類的子類對象
        return new Student();
    }
    
}

           

6.3 接口作為方法參數和傳回值

  • 接口作為方法的形參:【同抽象類】
  • 接口作為方法的傳回值:【同抽象類】
/*定義一個接口*/
public interface USB{
    public void run();
}
/*定義子類*/
public class Keyboard implements USB{
    public void run(){
        System.out.println("使用鍵盤...");
    }
}
public class Mouse implements USB{
    public void run(){
        System.out.println("使用滑鼠...");
    }
}
/*定義測試類*/
public class Test{
    public static void main(String[] args){
        //1.調用method1()方法,需要傳入USB的任何子類對象都可以
        method1(new Keyboard());
        method2(new Mouse());
        
        //2.調用method2()方法,此方法可能傳回一個Keyboard對象,也可能傳回一個Mouse對象
        USB usb = method2();
        usb.run();
    }
    //接口作為形參
    public static void method1(USB usb){
        usb.run();
    }
    //接口作為傳回值
    public static USB method2(){
  //      return new Keyboard();//OK的
    	return new Mouse();//OK的    
    }
}

           

6.4 類名作為成員變量

​ 我們每個人(Person)都有一個身份證(IDCard) , 為了表示這種關系 , 就需要在Person中定義一個IDCard的成員變量。定義Person類時,代碼如下:

class Person {
    String name;//姓名
    int age;//年齡
}

           

​ 使用

String

類型表示姓名 ,

int

類型表示年齡。其實,

String

本身就是引用類型,我們往往忽略了它是引用類型。如果我們繼續豐富這個類的定義,給

Person

增加身份證号 , 身份證簽發機關等屬性,我們将如何編寫呢?這時候就需要編寫一個IDCard類了

定義IDCard(身份證)類,添加身份證号 , 簽發地等屬性:

class IDCard {
    String idNum;//身份證号
    String authority;//簽發地
  
  	//getter和setter方法
  	//...
  	
  	//toString方法
  	//...
}

           

修改Person類:

public class Person {
    String name;//姓名
    int age;//年齡

    IDCard idCard;//表示自己的身份證資訊

    //name和age的getter、setter方法
    //...

    public IDCard getIdCard() {
        return idCard;
    }

    public void setIdCard(IDCard idCard) {
        this.idCard = idCard;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", idCard=" + idCard +
                '}';
    }
}

           

測試類:

public class TestDemo {
    public static void main(String[] args) {
        //建立IDCard對象
        IDCard idCard = new IDCard();
        //設定身份證号
        idCard.setIdNum("110113201606066666");
        //設定簽發地
        idCard.setAuthority("深圳市寶安區警察局");

        //建立Person對象
        Person p = new Person();
        //設定姓名
        p.setName("小順子");
        //設定年齡
        p.setAge(2);
        //設定身份證資訊
        p.setIdCard(idCard);

        //列印小順子的資訊
        System.out.println(p);
    }
}
輸出結果:
Person{name='小順子', age=2, idCard=IDCard{idNum='110113201606066666', authority='深圳市寶安區警察局'}}

           
類作為成員變量時,對它進行指派的操作,實際上,是賦給它該類的一個對象。同理 , 接口也是如此 , 例如我們筆記本案例中使用usb裝置。在此我們隻是通過小例子 , 讓大家熟識下引用類型的用法 , 後續在咱們的就業班學習中 , 這種方式會使用的很多。

6.5 抽象類作為成員變量

  • 抽象類作為成員變量——為此成員變量指派時,可以是任何它的子類對象
/*定義抽象類*/
public abstract class Animal{
    public abstract void sleep();
}
/*定義子類*/
public class Cat extends Animal{
    public void sleep(){
        System.out.println("小貓睡覺...");
    }
    public String toString(){
        return "一隻可愛的小貓";
    }
}

/*定義Student類*/
public class Student{
    private String name;
    private int age;
    private Animal animal;//表示學生有一個動物,可以是Cat,也可以是Dog
    
    public Student(String name,int age,Animal animal){
        this.name = name;
        this.age = age;
        this.animal = animal;
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
    public void setAge(int age){
        this.age = age;
    }
    public int getAge(){
        return this.age;
    }
    public void setAnimal(Animal animal){
        this.animal = animal;
    }
    public Animal getAnimal(){
        return this.animal;
    }
    
    public String toString(){
        return "Student [name = " + name + 
            	" , age = " + age + 
            	" , animal = " + animal + 
            	"]";
    }
}
/*定義測試類*/
public class Test{
    public static void main(String[] args){
        Student stu = new Student();
        stu.setName("章子怡");
        stu.setAge(19);
        stu.setAnimal(new Cat());//表示Student有一隻貓
        
        System.out.println(stu);//隐式調用stu.toString(),而stu.toString()中會隐式調用animal的toString().
    }
    
}

           

6.6 接口作為成員變量

  • 接口類型作為成員變量——【同抽象類】
/*定義接口*/
public interface Animal{
    public abstract void sleep();
}
/*定義子類*/
public class Cat implements Animal{
    public void sleep(){
        System.out.println("小貓睡覺...");
    }
    public String toString(){
        return "一隻可愛的小貓";
    }
}

/*定義Student類*/
public class Student{
    private String name;
    private int age;
    private Animal animal;//表示學生有一個動物,可以是Cat,也可以是Dog
    
    public Student(String name,int age,Animal animal){
        this.name = name;
        this.age = age;
        this.animal = animal;
    }
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }
    public void setAge(int age){
        this.age = age;
    }
    public int getAge(){
        return this.age;
    }
    public void setAnimal(Animal animal){
        this.animal = animal;
    }
    public Animal getAnimal(){
        return this.animal;
    }
    
    public String toString(){
        return "Student [name = " + name + 
            	" , age = " + age + 
            	" , animal = " + animal + 
            	"]";
    }
}
/*定義測試類*/
public class Test{
    public static void main(String[] args){
        Student stu = new Student();
        stu.setName("章子怡");
        stu.setAge(19);
        stu.setAnimal(new Cat());//表示Student有一隻貓  
        System.out.println(stu);//隐式調用stu.toString(),而stu.toString()中會隐式調用animal的toString().
    }
    
}

           

繼續閱讀