什么是內部類?內部類有哪些?怎么使用?——內部類用法


內部類

概念

定義在一個類內部的類叫做內部類
public class Demo3 {
}

class Outer{
    //
    class Inner{
        
    }
}

特點

每一個類都會生成一個單獨的字節碼文件

分類

1、成員內部類
2、靜態內部類
3、局部內部類
4、匿名內部類(最常用的一個內部類 也是jdk8中新特性Lambda的前提)

一、成員內部類

1、定義位置

外部類的成員位置

2、特點

特點:可以訪問外部類的私有成員⽽不破環封裝

案例:


public class Demo3 {
}

class Outer{
    private int a = 10;
    private void m(){
        System.out.println("我是外部類中的私有成員方法");
    }
    private static void m2(){
        System.out.println("我是外部類中的私有靜態方法");
    }
    //成員位置

    //成員內部類
    class Inner {
        public void m1(){
            System.out.println(a);//可以直接訪問外部類的私有成員而不破環封裝
            m();
            m2();
        }
    }

}

3、對象的創建方式

1. 先創建外部類對象
2. 通過外部類對象創建內部類對象

案例

//案例1: 關於成員內部類對象的創建
package com.ujiuye.day13;

public class Demo3 {
    public static void main(String[] args) {
        //創建成員內部類對象
        // 1 創建外部類對象
//        Outer outer = new Outer();//有名對象
          //new Outer();//匿名對象  只能使用一次
//
//        //2 通過外部類的對象 創建內部類的對象
//        // 類名 對象名  =  new 類名();
//        Outer.Inner inner = outer.new Inner();


        //簡寫
        Outer.Inner inner = new Outer().new Inner();
    }
}

class Outer{
    private int a = 10;
    private void m(){
        System.out.println("我是外部類中的私有成員方法");
    }
    private static void m2(){
        System.out.println("我是外部類中的私有靜態方法");
    }
    //成員位置

    //成員內部類  ---> 地位 就相當於 成員變量 和 成員方法的地位   隨着對象的創建而存在
    class Inner {
        public void m1(){
            System.out.println(a);//可以直接訪問外部類的私有成員而不破環封裝
            m();
            m2();
        }
    }

}

創建對象方式:

//方式一
 // 1 創建外部類對象
    Outer outer = new Outer();//有名對象
 // 2 通過外部類的對象 創建內部類的對象
    // 類名 對象名  =  new 類名();
    Outer.Inner inner = outer.new Inner();

//方式二
    //簡寫
    Outer.Inner inner = new Outer().new Inner();

4、注意事項

1. 當內部類存在和外部類成員變量重名問題 通過 外部類.this 訪問外部類的屬性
    this. 代表的是本類的引⽤
    外部類.this. 代表的是外部類的引⽤
2. 不能在成員內部類中創建靜態成員(因為 成員內部類的角色地位和成員變量是同等,也是隨着外部類的對象創建而存在  
    但是如果有靜態成員的話 內部類的類加載 先於外部類的類加載  ->矛盾

案例

//案例1: 關於注意事項1

public class Demo3 {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().new Inner();

        //調用方法
        inner.m1();
    }
}

class Outer{
    //外部類中成員變量 a
    private int a = 10;

    //成員內部類  ---> 地位 就相當於 成員變量 和 成員方法的地位   隨着對象的創建而存在
    class Inner {
        //成員內部類中的成員變量
        int a = 20;

        public void m1(){
            //成員內部類 中局部變量
            int a = 30;

            //訪問每個a
            System.out.println(a);//30
            // 在內部類中  本質上有  兩個this   內部類對象的this  外部類對象的引用this
            System.out.println(this.a);//默認Inner.this
            System.out.println(Inner.this.a);//20
            System.out.println(Outer.this.a);//10
        }
    }

}


//案例2: 關於注意事項2
package com.ujiuye.day13;

public class Demo3 {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer().new Inner();

        //調用方法
        inner.m1();
    }
}

class Outer{
    //外部類中成員變量 a
    private int a = 10;

    //成員內部類  ---> 地位 就相當於 成員變量 和 成員方法的地位   隨着對象的創建而存在
    class Inner {
        //成員內部類中的成員變量
        int a = 20;
        //static int b = 10;//不可以

//        public static void m2(){//不可以的
//
//        }

        public void m1(){
            //成員內部類 中局部變量
            int a = 30;

            //訪問每個a
            System.out.println(a);//30
            // 在內部類中  本質上有  兩個this   內部類對象的this  外部類對象的引用this
            System.out.println(this.a);//默認Inner.this
            System.out.println(Inner.this.a);//20
            System.out.println(Outer.this.a);//10
        }
    }

}

二、 靜態內部類

1、位置

在外部類中,和靜態成員並列  static 修飾的成員內部類

2、語法

static class 類名{
}

3、對象創建方式

語法:外部類類名.內部類類名 對象名 = new 外部類.內部類();

public class Demo3 {
    public static void main(String[] args) {
        //靜態內部類的對象創建
        // 靜態成員 可以通過 類名.直接放完  靜態內部類 也可以通過 外部類. 訪問內部類的類名
        // 靜態內部類 什么時候進行初始化? 靜態內部類 隨着 外部類 類加載的的進行而存在
        // 沒有必要創建外部類對象 直接通過類名.創建對象

        // 類名  對象名 = new  類名();   Outer.Inner 看成一個整體 
        Outer.Inner inner = new Outer.Inner();


    }
}

//外部類
class Outer{
    //靜態內部類
    static class Inner{

    }

}

4、特點

  靜態內部類中不能直接訪問外部類⾮靜態的成員

案例

//案例1:

public class Demo3 {
    public static void main(String[] args) {
        //靜態內部類的對象創建
        // 靜態成員 可以通過 類名.直接放完  靜態內部類 也可以通過 外部類. 訪問內部類的類名
        // 靜態內部類 什么時候進行初始化? 靜態內部類 隨着 外部類 類加載的的進行而存在
        // 沒有必要創建外部類對象 直接通過類名.創建對象

        // 類名  對象名 = new  類名();   Outer.Inner 看成一個整體
        Outer.Inner inner = new Outer.Inner();


    }
}

//外部類
class Outer {
    //外部類的屬性
    int a = 10;//外部類的成員變量
    static int b = 20;//外部類的靜態變量

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

    //外部類的靜態方法
    public static void m2() {
        System.out.println("我是外部類的靜態方法");
    }

    //靜態內部類
    static class Inner {

        //定義一個內部類的成員方法
        public void m3() {
//            System.out.println(a);//a是非靜態屬性
//            m1();//m1方法是非靜態方法

            //非要訪問 外部類的成員變量 和調用成員方法
            // 創建外部類的對象
//            Outer outer = new Outer();
//            System.out.println(outer.a);
//            outer.m1();

//            System.out.println(b);
//            m2();

        }

    }

}


//案例2:
public class Demo3 {
    public static void main(String[] args) {
        //靜態內部類的對象創建
        // 靜態成員 可以通過 類名.直接放完  靜態內部類 也可以通過 外部類. 訪問內部類的類名
        // 靜態內部類 什么時候進行初始化? 靜態內部類 隨着 外部類 類加載的的進行而存在
        // 沒有必要創建外部類對象 直接通過類名.創建對象

        // 類名  對象名 = new  類名();   Outer.Inner 看成一個整體
        Outer.Inner inner = new Outer.Inner();


    }
}

//外部類
class Outer {
    //外部類的屬性
    int a = 10;//外部類的成員變量
    static int b = 20;//外部類的靜態變量

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

    //外部類的靜態方法
    public static void m2() {
        System.out.println("我是外部類的靜態方法");
    }

    //靜態內部類
    static class Inner {
        int a = 10;
        static  int b = 20;
        //定義一個內部類的靜態方法
        public static void m3() {
            System.out.println(a);
            System.out.println(b);

        }

    }

}

//案例3:  關於重名問題
public class Demo3 {
    public static void main(String[] args) {
        //靜態內部類的對象創建
        // 靜態成員 可以通過 類名.直接放完  靜態內部類 也可以通過 外部類. 訪問內部類的類名
        // 靜態內部類 什么時候進行初始化? 靜態內部類 隨着 外部類 類加載的的進行而存在
        // 沒有必要創建外部類對象 直接通過類名.創建對象

        // 類名  對象名 = new  類名();   Outer.Inner 看成一個整體
        Outer.Inner inner = new Outer.Inner();

        inner.m();


    }
}

//外部類
class Outer {
    static int b = 20;//外部類的靜態變量

    //靜態內部類
    static class Inner {
        static  int b = 30;

        public void m(){

            System.out.println(b);//30
            System.out.println(this.b);
            System.out.println(Inner.b);

            System.out.println(Outer.b);
        }

    }

}

三、 局部內部類(重點)

1、位置

在外部類的⽅法中定義局部內部類, 局部位置  ---> 和 局部變量屬於一個等級 

2、語法

//定義外部類
class Outer{

     public void m1() {
         //定義局部內部類
         class Inner{

         }
     }

}

3、創建對象方式

局部內部類的對象只能在它所在的⽅法中   定義內部類語句之后創建

//案例:

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

    }
}
//外部類
class Outer {

    //外部類的成員方法
    public void m(){
        //局部位置
        //局部內部類  ---> 隨着 方法的壓棧而初始化
        // 局部內部類的 作用域  從定義行開始 到所在的最近的代碼塊結束
        class Inner{

        }
        //在定義局部內部類之后 才能創建對象
        Inner inner = new Inner();
    }
}


4、特點

1.在局部內部類中可以訪問外部類中的成員,局部內部類中不可以定義靜態成員
2.局部內部類訪問外部類的局部變量 要求這個局部變量必須是final修飾的 在jdk7中必須加final
	jdk8可以不加但是默認是final
//案例:
package com.ujiuye.day13;

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


    }
}

//外部類
class Outer {
    int a = 10;
    static  int b = 20;

    public void m1(){
        System.out.println("我是外部類的成員方法");
    }

    public static void m2(){
        System.out.println("我是外部類的靜態方法");
    }


    //外部類的成員方法
    public void m(){
        //局部位置
        //局部內部類  ---> 隨着 方法的壓棧而初始化
        // 局部內部類的 作用域  從定義行開始 到所在的最近的代碼塊結束
        class Inner{
            public void m3(){
                System.out.println(a);
                System.out.println(b);
                m1();
                m2();
            }
        }


    }
}


//案例2: 關於特點2

public class Demo3 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.m();

    }
}

//外部類
class Outer {
    int a = 10;//外部類的成員變量

    //外部類的成員方法
    public void m(){
        int a = 20;//外部類的局部變量
        class Inner{

            public void m3(){

                //用不到 外部類中的局部變量  ----> 就是沒有加final

                //用到 外部類中的局部變量  ---> 系統在jdk8之后 會默認加fianl  在jdk7之前 需要手動加final才能訪問
                System.out.println(a);//局部內部類可以訪問外部類的局部變量
            }
        }

        Inner inner = new Inner();
        inner.m3();


    }
}

案例3: 重名問題

public class Demo3 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.m();

    }
}

//外部類
class Outer {
    int a = 10;//外部類的成員變量a

    //外部類的成員方法
    public int m(){
        int a = 20;//外部類的局部變量a
        class Inner{
            int a = 30;//內部類的成員變量a

            public void m3(){
                int a = 40;//內部類的局部變量a
                //System.out.println(a);//40
//                System.out.println(this.a);//30
//                System.out.println(Inner.this.a);//30
               // System.out.println(Outer.this.a);//10
                // int a = 20; 這個a沒法訪問
//                Outer outer = new Outer();
//                int m = outer.m();
//                System.out.println(m);
            }
        }

        Inner inner = new Inner();
        inner.m3();

        return a;
    }
}

四、匿名內部類

1、概念

匿名內部類是非靜態內部類的一種特殊情況,匿名內部類沒有類名。優點: 可以讓程序員專注於代碼邏輯的實現,讓編程的思路更加的順利. 

2、要求

必須繼承一個類 或者 實現一個接口   ----> 這個類要想寫成匿名內部類的形式 必須要求 有親爹 或者有一個干爹

3、特點

一個匿名內部類只能創建一個對象

案例


import java.util.Scanner;
public class Demo5 {
    public static void main(String[] args) {

        // 1 可以直接通過學校獲取老師
        Scanner scanner = new Scanner(System.in);
        System.out.println("請輸入你的學號:");
        int code = scanner.nextInt();

        Teacher teacher = School.getTeacher(code);
        //老師上課
        teacher.teach();

        //2 老師現在不受學校的監管  -----> 違法  學校不允許
//        Liu liu = new Liu();
//        liu.teach();

        //3 學生還可以 通過去學校里 找到劉老師教Java  但是沒有經過選課系統
//        School.Liu liu = new School.Liu();
//
//        liu.teach();

        // 4站在學生的角度分析

        // 對於學生 來說:
    }
}

//定義一個學校類
class School{


    //功能 根據學號分配老師
    public static Teacher getTeacher(int code){
    
        if (code%2 == 0){
            //返回了一個  Teacher 接口的實現類對象 只不過這個類沒有名字
            return new Teacher(){//類沒有名字了 但是告訴系統 我是誰得兒子

                @Override
                public void teach() {
                    System.out.println("教Java");
                }
            };
        }else{
            return new Teacher(){

                @Override
                public void teach() {
                    System.out.println("教前端");
                }
            };
        }
    }
}

//接口
interface  Teacher{
    //規則
    void teach();
}

五、內部類的字節碼文件名的總結

  不管是外部類 還是 內部類 經過編譯最終都會形成一個單獨的字節碼文件,字節碼文件名和外部類類名有聯系

1、成員內部類
                內部類的字節碼文件名: 外部類類名$內部類類名.class
2、靜態內部類
		內部類的字節碼文件名: 外部類類名$內部類類名.class
3、局部內部類
		內部類字節碼文件名: 外部類類名$序號內部類類名.class   序號: 從 1開始的
4、匿名內部類
		內部類字節碼文件名: 外部類類名$序號.class  序號從 1開始編號


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM