1. 程式人生 > >【學習筆記】 唐大仕—Java程式設計 第5講 深入理解Java語言之5.5 內部類與匿名類

【學習筆記】 唐大仕—Java程式設計 第5講 深入理解Java語言之5.5 內部類與匿名類

/**
* 內部類與匿名類
* @author cnRicky
* @date 2018.11.10
*/
內部類與匿名類
  • 內部類(inner class)是在其他類中的類
  • 匿名類(anonymous class)是一種特殊的內部類,它沒有類名
內部類(Inner class)
  • 內部類的定義

    • 將類的定義class xxxx{...}置入一個類的內部即可
    • 編譯器生成xxxx$xxxx這樣的class檔案
    • 內部類不能夠與外部類同名
  • 內部類的使用

    • 在封裝它的內的內部使用內部類,與普通的使用方式相同
    • 在其他地方使用
      • 類名前要冠以外部類的名字
      • 在用new建立內部類時,也要在new前面冠以物件變數
      • 外部物件名.new 內部類名(引數)
class TestInnerClass{
    public static void main( String[] args ){
        Parcel p = new Parcel();
        p.testShip();

        Parcel.Contents c = p.new Contents(33);
        Parcel.Destination d = p.new Destination( "Hawii" );
        p.setProperty( c, d );
        p.ship();
    }
}

class Parcel { private Contents c; private Destination d; class Contents { private int i; Contents( int i ){ this.i = i; } int value() { return i; } } class Destination { private String label; Destination(String whereTo) {label = whereTo;} String readLabel() { return
label; } } void setProperty( Contents c, Destination d ){ this.c =c; this.d = d; } void ship(){ System.out.println( "move "+ c.value() +" to "+ d.readLabel() ); } public void testShip() { c = new Contents(22); d = new Destination("Beijing"); ship(); } }

 

在內部類中使用外部類的成員
  • 內部類中可以直接訪問外部類的欄位及方法

    • 即使private也可以
  • 如果內部類中有與外部類同名的欄位或方法,則可以用

    • 外部類名.this.欄位及方法
  • 例子:

class A
{
    private int s = 111;
    
    public class B{
        private int s = 222;
        public void mb(int s){
            System.out.println(s);//區域性變數s
            System.out.println(this.s);//內部類物件的屬性s
            System.out.println(A.this.s);//外層類物件屬性s
        }
    }
}

 

內部類的修飾符
  • 內部類與類中的欄位、方法一樣是外部類的成員,它的前面也可以有訪問控制符和其他修飾符
    • 訪問控制符:public、protected,預設(default)及private
      • 注:外部類只能夠使用public修飾或者預設
    • final,abstract
static修飾符
  • 用static修飾內部類,表名該內部類實際是一種外部類

    • 因為它與外部類的例項無關
    • 有人認為static的類是巢狀類(nested class),不是內部類(inner class)
  • static類在使用時:

    • 1、例項化static類時,在new前面不需要用物件例項變數;
    • 2、static類中不能訪問其外部類的非static的欄位及方法,即只能夠訪問static成員
    • 3、static方法中不能訪問非static的域及方法,也不能夠不帶字首地new一個非static的內部類
  • 例子:

public class TestInnerStatic
{
    public static void main(String[] args)
    {
        A.B a_b = new A().new B();//ok
        A a = new A();
        A.B ab = a.new B();
        
        Outer.Inner oi = new Outer.Inner();
        //Outer.Inner oi2 = new Outer.new Inner();//!!!error
        //Outer.Inner oi3 = new Outer().new Inner();//!!!error
    }
}

class A
{
    private int x;
    void m(){
        new B();
    }
    static void sm(){
        //new B();//error!!!
    }
    class B
    {
        B(){ x = 5; }
    }
}
class Outer
{
    static class Inner
    {
        
    }
}

 

區域性類
  • 在一個方法中也可以定義類,這種類稱為“方法中的內部類”
  • 或者叫區域性類(local class)
  • 例子:
class TestInnerInMethod
{
    public static void main(String[] args)
    {
        Object obj = new Outer().makeTheInner(47);
        System.out.println("Hello World!" + obj.toString());
    }
}

class Outer
{
    private int size = 5;
    public Object makeTheInner(int localVar)
    {
        final int finalLocalVar = 99;
        class Inner{
            public String toString(){
                return("InnerSize:" + size +
                      // "localVar:" + localVar + //Error!
                       "finalLocalVar:" + finalLocalVar
                      );
            }
        }
        return new Inner();
    }
}

 

使用區域性類
  • 1、同區域性變數一樣,方法中的內部類

    • 不能夠用public,private,protected,static修飾
    • 但可以被final或者abstract修飾
  • 2、可以訪問其外部類的成員

  • 3、不能夠訪問該方法的區域性變數,除非是final區域性變數

匿名類
  • 匿名類(anonymous class)是一種特殊的內部類

    • 它沒有類名,在定義類的同時就生成該物件的一個例項
    • “一次性使用”的類
  • 例子:

class TestInnerAnonymous
{
    public static void main(String[] args) 
    {
        
    }
}

class Outer
{
    private int size = 5;
    public Object makeTheInner(int localVar)
    {
        final int finalLocalVar = 99;
        return new Object(){
            public String toString(){
                return ("InnerSize:" + size + "finalLocalVar:" + finalLocalVar);
            }
        };
    }
}

 

匿名類的使用
  • 1、不取名字,直接用其父類或介面的名字

    • 也就是說,該類是父類的子類,或者實現了一個介面
    • 編譯器生成xxxxx$之類的名字
  • 2、類的定義的同時就建立例項,即類的定義前面有一個new

    • new 類名或介面名(){ ...... }
    • 不使用關鍵字class,也不使用extends及implements
  • 3、在構造物件時使用父類構造方法

    • 不能夠定義匿名類的構造方法,因為它沒有名字
    • 如果new物件時,要帶引數,則使用父類的構造方法
匿名類的應用
  • 用到介面的事件處理
    • 註冊一個事件監聽器
    • 示例AutoScore.java中
//SymAction ISymAction = new SymAction();
//btnNew.addActionListener(ISymAction);

btnNew.addActionListener(new ActionListener(){
   public void actionPerformed(ActionEvent event)
   {
       ......;
   }
});

 

  • 作為方法的引數
    • 排序,給一個比較大小的介面
    • 如:
Arrays.<Book>sort(books, new Comparator<Book>(){
    public int compare(Book b1, Book b1){
        return b1.getPrice()-b2.getPrice();
    } 
});