1. 程式人生 > >JAVA內部類總結筆記

JAVA內部類總結筆記

 內部類分為四類:成員內部類、區域性(作用域)內部類、匿名內部類、靜態內部類。

內部類大比拼
成員內部類 區域性(作用域)內部類 匿名內部類 靜態內部類
訪問修飾符

成員內部類

 就像一個成員變數和方法一樣,你說她有沒有修飾符?有的呀!同時可以訪問外部類的靜態/非靜態變數和方法。

若內部類擁有與外部類同名成員(變數/方法),預設訪問成員內部類。訪問外部 外部類.this.成員(變數/方法)

綜上:想成員一樣的成員內部類,使用時需要先建立外部物件。

public class Outter {
    private Inner inner = null;

    public void printMsg() {
        System.out.println("我是一個快樂的外部類");
    }

    public class Inner {

        public void printMsg() {
            System.out.println("我是一個快樂的內部類");
        }

        public void printAgain() {
            this.printMsg();
            Outter.this.printMsg();
        }
    }

    /**
     * 聽說使用getXXX的方式獲取例項物件會更優雅哦
     */
    public Inner getInner() {
        if (null == inner)
            inner = new Inner();
        return inner;
    }

    public static void main (String[] args) {
        //建立外部類物件
        Outter outter = new Outter();
        Outter.Inner inner = outter.new Inner();
        Inner inner2 = outter.getInner();
        inner.printMsg();
        inner2.printMsg();
        outter.printMsg();
        inner.printAgain();
    }
}

列印結果:

這是我隨手寫的一個醜陋的內部類。printAgain寫了在內部類呼叫同名外部類成員的方式。

區域性內部類

  聯想一下,區域性?區域性變數啥的,作用域是區域性的。這裡的區域性內部類是指方法內定義內部類和作用域內定義內部類。她們的訪問許可權僅限方法/作用域

她們有修飾符嗎?你想想,你家方法內部的變數寫修飾符了嗎?小傻瓜。

public class Outter {
    private MemberInner inner = null;

    public void printMsg() {
        System.out.println("Outter.printMsg: 我是一個快樂的外部類");
    }

    /**
     * 成員內部類
     */
    public class MemberInner {

        public void printMsg() {
            System.out.println("Inner.printMsg: 我是一個快樂的內部類");
        }

        public void printAgain() {
            //他自己
            this.printMsg();
            //他外面的
            Outter.this.printMsg();
        }
    }

    /**
     * 聽說使用getXXX的方式獲取例項物件會更優雅哦
     */
    public MemberInner getInner() {
        if (null == inner)
            inner = new MemberInner();
        return inner;
    }

    public MemberInner ordinaryMethod() {
        /**
        *區域性內部類-方法內
        */
         class LocalInner extends MemberInner{
             @Override
            public void printMsg() {
                System.out.println("LocalInner.printMsg: 人家才不是成員內部類呢,我是一個可愛的方法內區域性內部類啊!");
            }
        }
        return new LocalInner();
    }

    public void anotherOrdinaryMethod (Boolean isTrue) {
        if (isTrue) {
            /**
            *區域性內部類-作用域
            */
            class AnotherLocalInner {
                public void printMsg() {
                    System.out.println("AnotherLocalInner.printMsg: 我是一個可愛的作用域內部類啊!");
                }
            }
            this.printMsg();
            printMsg();
            new AnotherLocalInner().printMsg();

        }
    }

    public static void main (String[] args) {
        //建立外部類物件
        Outter outter = new Outter();

        //成員內部類
        Outter.MemberInner inner = outter.new MemberInner();
        MemberInner inner2 = outter.getInner();
        inner.printMsg();
        inner2.printMsg();
        outter.printMsg();
        inner.printAgain();
        System.out.println("----------------------華麗麗的分割線---------------------");
        //區域性內部類
        outter.ordinaryMethod().printMsg();
        outter.anotherOrdinaryMethod(true);
    }
}

列印結果:

Inner.printMsg: 我是一個快樂的內部類
Inner.printMsg: 我是一個快樂的內部類
Outter.printMsg: 我是一個快樂的外部類
Inner.printMsg: 我是一個快樂的內部類
Outter.printMsg: 我是一個快樂的外部類
----------------------華麗麗的分割線---------------------
LocalInner.printMsg: 人家才不是成員內部類呢,我是一個可愛的方法內區域性內部類啊!
Outter.printMsg: 我是一個快樂的外部類
Outter.printMsg: 我是一個快樂的外部類
AnotherLocalInner.printMsg: 我是一個可愛的作用域內部類啊!

Process finished with exit code 0

綜上:無

匿名內部類

  感覺大多是用在swing程式設計,監聽事件啊、介面回撥什麼的。對繼承方法的重寫或者實現什麼的。

沒有修飾符,由於沒有名字(類名),可憐得連構造方法也沒有QAQ(不能定義構造方法,但有內部程式碼塊來初始化引數)。

public class Outter {
    private MemberInner inner = null;

    public void printMsg() {
        System.out.println("Outter.printMsg: 我是一個快樂的外部類");
    }

    /**
     * 成員內部類
     */
    public class MemberInner {

        public void printMsg() {
            System.out.println("Inner.printMsg: 我是一個快樂的內部類");
        }

        public void printAgain() {
            //他自己
            this.printMsg();
            //他外面的
            Outter.this.printMsg();
        }
    }

    /**
     * 聽說使用getXXX的方式獲取例項物件會更優雅哦
     */
    public MemberInner getInner() {
        if (null == inner)
            inner = new MemberInner();
        return inner;
    }

    /**
     * 內部類使用了方法的形參age
     */
    public MemberInner ordinaryMethod(int age) {
        /**
        *區域性內部類-方法內
        */
         class LocalInner extends MemberInner{
             @Override
            public void printMsg() {
                 System.out.println("倫家今年" + (age) + "歲呢");
                 System.out.println("LocalInner.printMsg: 人家才不是成員內部類呢,我是一個可愛的方法內區域性內部類啊!");
            }
        }
        return new LocalInner();
    }

    public void anotherOrdinaryMethod (Boolean isTrue) {
        if (isTrue) {
            /**
            *區域性內部類-作用域
            */
            class AnotherLocalInner {
                public void printMsg() {
                    System.out.println("AnotherLocalInner.printMsg: 我是一個可愛的作用域內部類啊!");
                }
            }
            this.printMsg();
            printMsg();
            new AnotherLocalInner().printMsg();

        }
    }

    public void getAnonymousInner(AnonymousInner anonymousInner) {
        System.out.println("這麼可愛一定是" + anonymousInner.whatSex() + "吧!");
    }

    /**
     * 內部類使用方法形參
     */
    public AnonymousInner transferValue(String sex) {
        return new AnonymousInner() {
            @Override
            public String whatSex() {
                return sex;
            }
        };
    }

    public static void main (String[] args) {
        //建立外部類物件
        Outter outter = new Outter();

        //成員內部類
        Outter.MemberInner inner = outter.new MemberInner();
        MemberInner inner2 = outter.getInner();
        inner.printMsg();
        inner2.printMsg();
        outter.printMsg();
        inner.printAgain();
        System.out.println("----------------------華麗麗的分割線---------------------");
        //區域性內部類
        outter.ordinaryMethod(12).printMsg();
        outter.anotherOrdinaryMethod(true);
        System.out.println("----------------------華麗麗的分割線---------------------");
        //匿名內部類
        outter.getAnonymousInner(new AnonymousInner() {
            @Override
            public String whatSex() {
                return "男孩子";
            }
        });
        outter.getAnonymousInner(outter.transferValue("女孩子"));
    }
}

/**
 * 匿名內部類的抽象類
 */
abstract class AnonymousInner {
    public abstract String whatSex();
}

在方法ordinaryMethod中,使用了外部方法的形參age,在我試圖修改age時,ide提示錯誤:

Variable 'age' is accessed from within inner class,needs to be final or effectively final

變數age是在內部類中訪問的,需要時final修飾的或是實際上的最終變數

*在以前內部類相關博文中提到,區域性內部類和匿名內部類使用外部類區域性變數或形參時必須是final,但在JAVA8中不再必須final了,是effectively final也支援。即只要你不去修改外部區域性變數/形參的值,則視為effectively final,就不會報錯。

關於JAVA8以前必須使用final修飾的原因

首先,一個有內部類的類,在編譯器編譯時,會將內部類單獨編譯成一個class檔案,即有兩個class檔案。內部類不是直接使用傳遞引數,而是通過拷貝備份(利用自身構造器)的方式來使用,所以如果內部類使用的變數和外部方法的變數不是同一個,在內部類中變數發生變化,會造成資料的不一致性,因此用final來限定區域性變數和形參的不可變。

靜態內部類

想一想,不充錢你會變得更強嗎?

想一想,你在用你的工具類的時候需要去new她嗎?不。

所以,不需要外部類先去建立例項物件。因此可以推斷,他(靜態內部類)也不能使用外部類的非靜態成員(變數/方法),因為外部類非靜態成員是依賴具體物件的。

public class AnotherOutter {
    public static class StaticInner {
        public void printMsg() {
            System.out.println("想一想,不充錢?你會變得更強嗎?----靜態內部類");
        }
    }

    public static void main (String[] args) {
        StaticInner staticInner = new StaticInner();
        staticInner.printMsg();
    }
}

class Strangers {
    public static void main (String[] args) {
        AnotherOutter.StaticInner staticInner = new AnotherOutter.StaticInner();
        staticInner.printMsg();
    }
}

關於內部類的總結就到這裡了,如果有錯誤的地方歡迎各位指正,謝謝(づ ̄3 ̄)づ╭❤~。