天天看點

第二階段-Java面向對象:【第七章 内部類】

(一)

内部類概述

把類定義在另一個類的内部,該類就被稱為内部類。

舉例:把類Inner定義在類Outer中,類Inner就被稱為内部類。

class Outer {
   class Inner {
   }
}           

複制

第二階段-Java面向對象:【第七章 内部類】

(二)

内部類的通路規則

A:可以直接通路外部類的成員,包括私有

B:外部類要想通路内部類成員,必須建立對象

第二階段-Java面向對象:【第七章 内部類】

(三)

内部類的分類

A:成員内部類

B:局部内部類

C:靜态内部類

D:匿名内部類

(1) 成員内部類

成員内部類——就是位于外部類成員位置的類

特點:可以使用外部類中所有的成員變量和成員方法(包括private的)

A:格式:
class Outer {
     private int age = 20;
 //成員位置
     class Inner {
         public void show() {
             System.out.println(age);
         }
     }
 }
 
 class Test {
     public static void main(String[] ages) {
 //成員内部類是非靜态的示範
         Outer.Inner oi = new Outer.new Inner();
         oi.show();
     }
 }           

複制

B:建立對象時:
//成員内部類不是靜态的:
 外部類名.内部類名 對象名 = new 外部類名.new 内部類名();
 
 //成員内部類是靜态的:
 外部類名.内部類名 對象名 = new 外部類名.内部類名();           

複制

C:成員内部類常見修飾符:

A:private

如果我們的内部類不想輕易被任何人通路,可以選擇使用private修飾内部類,這樣我們就無法通過建立對象的方法來通路,想要通路隻需要在外部類中定義一個public修飾的方法,間接調用。這樣做的好處就是,我們可以在這個public方法中增加一些判斷語句,起到資料安全的作用。

class Outer {
     private class Inner {
         public void show() {
             System.out.println(“密碼備份檔案”);
         }
     }
     
     public void method() {
      if(你是管理者){
       Inner i = new Inner();
       i.show();
      }else {
       System.out.println(“你沒有權限通路”);
      }
     }
 }           

複制

下面我們給出一個更加規範的寫法

class Outer {
     private class Inner {
         public void show() {
             System.out.println(“密碼備份檔案”);
         }
     }
 //使用getXxx()擷取成員内部類,可以增加校驗語句(文中省略)
     public void getInner() {
   return new Inner();
     }
     
     public static void main(String[] args) {
      Outer outer = new Outer();
         Outer.Inner inner = outer.getInner();
         inner.show();
     }
 }           

複制

B:static

這種被 static 所修飾的内部類,按位置分,屬于成員内部類,但也可以稱作靜态内部類,也常叫做嵌套内部類。具體内容我們在下面詳細講解。

D:成員内部類經典題(填空)

請在三個println 後括号中填空使得輸出25,20,18

class Outer {
  public int age = 18; 
  class Inner {
   public int age = 20; 
   public viod showAge() {
    int age  = 25;
    System.out.println(age);//空1
    System.out.println(this.age);//空2
    System.out.println(Outer.this.age);//空3
   }
  }
 }           

複制

(2) 局部内部類

局部内部類——就是定義在一個方法或者一個作用域裡面的類

特點:主要是作用域發生了變化,隻能在自身所在方法和屬性中被使用

A 格式:

class Outer {
     public void method(){
         class Inner {
         }
     }
 }           

複制

B:通路時:

//在局部位置,可以建立内部類對象,通過對象調用和内部類方法
 class Outer {
     private int age = 20;
     public void method() {
         final int age2 = 30;
         class Inner {
             public void show() {
                 System.out.println(age);
 //從内部類中通路方法内變量age2,需要将變量聲明為最終類型。
                 System.out.println(age2);
             }
         }
         
         Inner i = new Inner();
         i.show();
     }
 }           

複制

C: 為什麼局部内部類通路局部變量必須加final修飾呢?

因為局部變量是随着方法的調用而調用,使用完畢就消失,而堆記憶體的資料并不會立即消失。

是以,堆記憶體還是用該變量,而該變量已經沒有了。為了讓該值還存在,就加final修飾。

原因是,當我們使用final修飾變量後,堆記憶體直接存儲的是值,而不是變量名。

(即上例 age2 的位置存儲着常量30 而不是 age2 這個變量名)

(3) 靜态内部類

我們所知道static是不能用來修飾類的,但是成員内部類可以看做外部類中的一個成員,是以可以用static修飾,這種用static修飾的内部類我們稱作靜态内部類,也稱作嵌套内部類.

特點:不能使用外部類的非static成員變量和成員方法

解釋:非靜态内部類編譯後會預設的儲存一個指向外部類的引用,而靜态類卻沒有。

簡單了解:

即使沒有外部類對象,也可以建立靜态内部類對象,而外部類的非static成員必須依賴于對象的調用,靜态成員則可以直接使用類調用,不必依賴于外部類的對象,是以靜态内部類隻能通路靜态的外部屬性和方法。

class Outter {
     int age = 10;
     static age2 = 20;
     public Outter() {        
     }
      
     static class Inner {
         public method() {
             System.out.println(age);//錯誤
             System.out.println(age2);//正确
         }
     }
 }
 
 public class Test {
     public static void main(String[] args)  {
         Outter.Inner inner = new Outter.Inner();
         inner.method();
     }
 }           

複制

(4) 匿名内部類

一個沒有名字的類,是内部類的簡化寫法

A 格式:

new 類名或者接口名() {
     重寫方法();
 }           

複制

本質:其實是繼承該類或者實作接口的子類匿名對象

這也就是下例中,可以直接使用 new Inner() {}.show(); 的原因 == 子類對象.show();

interface Inter {
  public abstract void show();
 }
 
 class Outer {
     public void method(){
         new Inner() {
             public void show() {
                 System.out.println("HelloWorld");
             }
         }.show();
     }
 }
 
 class Test {
  public static void main(String[] args)  {
      Outer o = new Outer();
         o.method();
     }
 }               

複制

如果匿名内部類中有多個方法又該如何調用呢?

Inter i = new Inner() {  //多态,因為new Inner(){}代表的是接口的子類對象
  public void show() {
  System.out.println("HelloWorld");
  }
 };           

複制

B:匿名内部類在開發中的使用

我們在開發的時候,會看到抽象類,或者接口作為參數。

而這個時候,實際需要的是一個子類對象。

如果該方法僅僅調用一次,我們就可以使用匿名内部類的格式簡化。