1. 程式人生 > >Java內部類(成員內部類、靜態內部類、方法內部類、匿名內部類)

Java內部類(成員內部類、靜態內部類、方法內部類、匿名內部類)

內部類 內部類是定義在一個類內部進行其他類結構的巢狀的操作。 為什麼存在內部類?1.首先看下內部類和不用內部類實現相同功能的程式碼: 不用內部類

//////不用內部類
class Outter
{
    private String msg="pick";
    public String Getmsg()
    {
        return msg;
    }
    public void fun()//3
    {
        Inner in=new Inner(this);//4
        in.Print();
    }
}
class Inner
{
    private Outter out;
    public void Print()
    {
        System.out.println(out.Getmsg());
    }
    public Inner(Outter out)
    {
        this.out=out;
    }
}
public class Out
{
    public static void main(String[] args)
    {
        Outter out=new Outter();//1
        out.fun();//2
    }
}

用內部類

/////用內部類
class Outter
{
    private String msg="pick";
    class Inner  
    {
        public void Print()
        {
            System.out.println(msg);  //可以發現內部類可以直接訪問外部類屬性
        }
    }
    //在外部類中定義一個方法,該方法負責產生內部類物件,並呼叫Print
    public void fun()
    {
        Inner in=new Inner();
        in.Print();
    }
}
public class Out
{
    public static void main(String[] args)
    {
        Outter out=new Outter();
        out.fun();
    }
}

可以發現兩種方法實現相同的功能,用或不用內部類程式碼複雜程度不同,直接原因是內部類可以直接訪問外部類私有屬性。 2.內部類可以模擬實現多繼承:

///內部類可以實現多繼承
class A
{
    private String name="pick";
    public String Getname()
    {
        return name;
    }
}
class B
{
    private int age=18;
    public int Getage()
    {
        return age;
    }
}

class C
{
    class ExtendA extends A   //ExtendA 繼承A
    {
        public String Name()
        {
            return new A().Getname();  // 返回父類A的屬性name
        }
    }
    class ExtendB extends B // ExtendB 繼承B
    {
        public int Age()
        {
            return new B().Getage();//返回父類B的屬性年齡
        }   
    }
    public String name()
    {
        return new ExtendA().Name();  //返回內部類的Name,相當於A的name
    }
    public int age()
    {
        return new ExtendB().Age(); //返回內部類的Age,相當於B的age
    }
    //C類現在既有A的屬性name,也有B的屬性age,模擬實現了多繼承
}
public class Out
{
    public static void main(String[] args)
    {
        C c=new C();
        System.out.println(c.name()); //pick
        System.out.println(c.age());  //18 
    }
}

3.內部類是另外一種封裝,內部類具有保護性,對外部其他類不可見: 在這裡插入圖片描述 在主類中無法直接訪問或者建立內部類 所以內部類存在原因如下:

  • 內部類可以直接訪問外部類的私有域(包括私有屬性和私有方法)

  • 內部類是另外一種封裝(保護性),對外部的其他類隱藏(心臟包在人身體內部)

  • 內部類可以實現Java單繼承的侷限。 但是內部類也存在缺點:結構複雜。 建立內部類在外部類內部建立內部類 內部類 內部類引用=new 內部類(); Inner in=new Inner( ); (可參考上文中不用內部類程式碼) 在外部類外部建立內部類

  • 在外部類外部建立非靜態內部類

外部類.內部類 內部類引用 =new 外部類( ).new 內部類( );

Outter.Inner in =new Outter( ).new Inner( );

//在外部類外部建立非靜態內部類
class Outter
{
    class Inner
    {
        public String name="pick";
        public void show()
        {
            System.out.println("hello day");
        }
        
    }
}
public class Out
{
    public static void main(String[] args)
    {
        Outter.Inner in=new Outter().new Inner(); 
        System.out.println(in.name);  //pick
        in.show(); //hello day
    }
}
  • 在外部類外部建立靜態內部類

外部類.內部類 內部類引用=new 外部類.內部類( ); Outter.Inner in=new Outter( ).Inner( );

//建立非靜態內部類
class Outter
{
    static class Inner
    {
        public String name="pick";
        public void show()
        {
            System.out.println("hello day");
        }    
    }
}
public class Out
{
    public static void main(String[] args)
    {
        Outter.Inner in=new Outter.Inner(); 
        System.out.println(in.name);  //pick
        in.show(); //hello day
    }
}

內部類與外部類的關係

  • 內部類是一個相對獨立的個體,與外部類沒有is-a關係;
  • 對於非靜態內部類,內部類的建立需要依賴外部類物件,在外部類沒有例項化前無法建立非靜態內部類。
  • 內部類可以直接訪問外部類的元素(包括私有域),但是外部類不可以直接訪問內部類元素,需要通過內部類的引用間接訪問。 內部類對外部類的直接訪問:
class Outter
{
    private String name;
    private int age;
    class Inner
    {
        public Inner()
        {
           Outter.this.name="pick"; //如果用this,必須先找到外部類
           age=18;
        }
        public void fun()
        {
            System.out.println(name);
        }
    }   
}
public class Out
{
    public static void main(String[] args)
    {
        Outter.Inner in=new Outter().new Inner();
        in.fun();
    }
}

外部類通過內部類的引用間接訪問內部類元素:

//外部類訪問內部類
class Outter
{
    class Inner
    {
        private String name;
        public void print()
        {
            System.out.println("Inner");
        }
    }
    public void show()
    {
        Inner in=new Inner();
        System.out.println(in.name);  //內部類的引用間接訪問內部類元素
        //System.out.println(name);  //錯誤,不能直接訪問
        in.print();
    }    
}

內部類的分類

成員內部類(類比成員方法)

  • 成員內部類不能存在任何static變數或方法,可以訪問外部類的靜態域;

  • 成員內部類依賴外部類,只有先建立外部類才能建立內部類;在編譯完成之後會隱含的儲存一個引用,該引用指向建立它的外部類; 靜態內部類(類比靜態方法)

  • 使用static修飾的內部類為靜態內部類

  • 靜態內部類沒有指向外部類的引用,所以靜態內部類的建立不需要依賴外部類,可以直接建立;

  • 靜態內部類不可以使用任何外部類的非static域(包括屬性與方法),可以使用外部類的static域,但是可以存在自己的成員變數 靜態內部類不可以訪問外部成員變數,但是可以擁有成員變數; 成員內部類不可以擁有靜態變數,但可以訪問外部靜態變數;因為靜態變數和物件無關,是在編譯時載入類存在的。 方法內部類

////方法內部類
class Outter
{
    private int num=10;
    public void func(int tmp)  //該tmp是final宣告,只是JDK8將形參變為隱式final宣告
    {
        //方法內部類
        class Inner
        {
            public void show()
            {
                //++tmp; //不可以修改,tmp是final宣告
                System.out.println(tmp);
                System.out.println(num); //方法內部類可以訪問方法外的屬性,但是方法外訪問不了方法內部類屬性
            }
        }
        new Inner().show();
    }
}
public class Out
{
    public static void main(String[] args)   
    {
        Outter out=new Outter();
        out.func(19);  //  19  10
    }
}
  • 方法內部類不允許使用訪問許可權修飾符,public/private/protected均不允許;
  • 方法內部類對外部完全隱藏,除了建立這個類的方法可以訪問它以外,其他地方均不能訪問;
  • 方法內部類如果想要使用方法形參,該形參必須使用final宣告。(JDK8將形參變為隱式final宣告) 建立方法內部類 的方法形參是final宣告,不可以修改: 在這裡插入圖片描述

匿名內部類(lamdba表示式前身) 匿名內部類就是一個沒有名字的方法內部類。因此特點與方法內部類完全一樣,除此之外,還有兩個自己的特點:

  • 匿名內部類必須繼承一個抽象類或者實現一個介面;
  • 匿名內部類沒有構造方法,因為它沒有類名 。但是方法內部類有構造方法。
//////匿名內部類:是特殊的方法內部類
interface Myinterface  //宣告一個介面
{
    void print();//抽象方法:沒有方法體
}
class Outter
{
    private int num=5;
    public void func(int tmp)
    {
        //匿名內部類,匿名的實現了Myinterface介面
        new Myinterface()
        {
            public void print()
            {
                System.out.println("匿名實現Myinterface介面");      
                System.out.println(tmp); 
                System.out.println(num);    
            }
        }.print();
    }
}
public class Out
{
    public static void main(String[] args)
    {
        Outter out=new Outter();
        out.func(10);  //  匿名實現Myinterface介面   10  5 
    }
}

注:如果發現類名稱上出現了“.”,就是內部類。