天天看點

Java 内部類詳解(成員内部類、靜态内部類、局部内部類、匿名内部類)

内部類概念:

一個類定義在另外一個類内部,就稱它為内部類。
           

内部類的應用場景

我們在描述A事物的時候,發現描述的A事物内部還存在另外一個比較複雜的B事物時候,而且這個比較複雜B事物還需要通路A事物的屬性等資料,那麼這時候我們就可以使用内部類描述B事物。

比如: 人--->心髒
class 人{
    血
    氧氣
    等....
    class 心髒{
    }       
}
           

内部類的好處:

内部類可以直接通路外部類的所有成員。
           

内部類還有一些更細的區分:

1、成員内部類

一個類定義在另外一個類成員變量的位置,就稱它為成員内部類。

成員内部類的通路方式

方式一:在外部類提供一個方法建立内部類的對象進行通路。

方式二:在其他類直接建立内部類的對象。 
格式:外部類.内部類 變量名 = new 外部類().new 内部類();

注意: 如果是一個靜态内部類,那麼在其他類建立 的格式:
             外部類.内部類  變量名 = new 外部類.内部類()。
           

内部類要注意的細節

1. 如果外部類與内部類存在同名的成員變量時,在内部類中預設情況下是通路内部類的成員變量。可以通過"外部類.this.成員變量名" 指定通路外部類的 成員。

2. 私有的成員内部類隻能在外部類提供一個方法建立内部類的對象進行通路,不能在其他類建立對象了。

3. 成員内部類一旦出現了靜态的成員,那麼該類也必須 使用static修飾。
原因:靜态成員變量通路不需要對象,如果内部類不是靜态的,不能通過類名直接通路内部類中的靜态變量。
           

代碼示例:

//外部類
class Outer{
    //成員變量
    int x = ;

    //成員内部類
    static  class Inner{
        //靜态成員在class被加載到記憶體的時候就存在記憶體中了   
        static  int i = ;
        int x = ;

        public void print(){
            System.out.println("這個是成員内部類的print方法!"+i);
            //非靜态内部類時,内外部成員變量重名時,使用外部類.this.外部類成員,通路重名的外部類成員
            //System.out.println("這個是成員内部類的print方法!" + Outer.this.x);
        }
    }

    //在外部的方法中建立了内部類的對象,然後調用内部方法。
    public void instance(){
        Inner inner = new Inner();
        inner.print();
    }
}

//其他類
class Demo 
{
    public static void main(String[] args) 
    {
        /*
        System.out.println(Outer.Inner.i);

        Outer outer = new Outer();
        outer.instance();

        //非靜态成員内部類時,内部類對象的建立
        Outer.Inner inner = new Outer().new Inner();
        inner.print();
        */

        //靜态成員内部類時,内部類對象建立
        Outer.Inner inner = new Outer.Inner();
        inner.print();
    }
}
           

2、靜态内部類

靜态類就是靜态内部類。
如果一個類要被聲明為static的,那麼隻有一種情況,就是靜态内部類。
           

靜态類建立格式:

外部類.内部類  變量名 = new 外部類.内部類()
           

3、局部内部類

一個類定義在另外一個類方法内的局部變量的位置,就稱它為局部内部類。
如果局部内部類通路了一個局部變量,那麼該局部變量必須使用final修飾!
           

原因:

當方法執行完畢後,局部變量就從記憶體中消失了,而局部内部類對象還沒有消失,但是假若具體内部類中方法還通路着這個局部變量的話,就會存在問題!
是以java虛拟機的做法是讓這個局部内部類方法通路這個局部變量的複制變量,但是這個複制變量是在通路時就已經确認了,且不會變化,是以被通路的局部變量也要是不能變化的!
           
class  Outer{
    String name= "外部類的name";
    public void test(){
        //局部變量
        int y =;  // y 什麼時候從記憶體中消失? 方法執行完畢之後y消失。

        //局部内部類
        class Inner{     
            int x = ;
            public void print(){
                System.out.println("這個是局部内部類的print方法.."+y);
            }   
        }   
        Inner inner = new Inner();  //這個inner對象什麼時候消失?  Inner對象是要在釋放的時候,才會消失。
        inner.print();
    }
}

class Demo
{
    public static void main(String[] args) 
    {
        Outer outer = new Outer();
        outer.test();
    }
}
           

4、匿名内部類

匿名内部類:

沒有類名的類就稱作為匿名内部類,
雖然沒有類名,但是類的其他成員都是存在的。
           

匿名内部類的使用前提:

必須存在抽象類繼承或者接口實作關系才能使用。
           

匿名内部類一般是用于實參:

隻是用一次,不需要具體的類對象。
           

代碼示例:

abstract class Animal{
    int i = ;
    public abstract Animal run();
    public abstract void sleep();
}

class Outer{
    public void print(){
        // 匿名内部類與Animal是繼承的關系
        //建立Animal子類的對象,這裡使用的是多态,父類的引用變量指向子類的對象
        Animal a = new Animal(){ 
            //匿名内部的成員 
            public Animal run(){
                System.out.println("狗在跑.." + i);
            }

            public void sleep(){
                System.out.println("狗趴在睜開眼睛睡..");
            }

            //特有的方法
            public void bite(){
                System.out.println("狗在咬人..");
            }

        };

        //無法通路特有方法,因為這裡使用的是父類的引用變量,隻能使用父類的方法
        //a.bite();
        a.run();
        a.sleep();
    }
}

class Demo
{
    public static void main(String[] args) 
    {
        Outer outer = new Outer();
        outer.print();
    }
}