Java 中的內部類


前言

在第一次把Java 編程思想中的內部類這一章擼完后,有點印象。大概知道了什么時內部類,局部內部類,匿名內部類,嵌套內部類。隨着時間的推移,自己慢慢的就忘記了,總感覺自己思考的東西不多,於是
看了第二遍,並把自己的想法和一些筆記寫下來。供以后參考。

內部類

定義:如果把A類定義再B類里面,那么把A類叫做 內部類

代碼如下:


public class B {
	public class A{}
}

這樣看內部類是不是感覺很簡單?定義確實很簡單,但是思考一下,這樣定義一個內部類有什么意義嗎?或者說能帶來什么好處? 上面那樣定義,個人感覺是意義不大。所以 ,我們一般定義內部類,都是需要內部類實現一個接口或着抽象類。有實際意義的代碼如下(例子來自,java編程思想):

/**
 * @ClassName Selector
 * @Description 選擇器
 * @Author ouyangkang
 * @Date 2019-03-12 14:21
 **/
public interface Selector {

    // 是否結束
    boolean end();

    // 當前數據
    Object current();

    // 下一個節點
    void next();
}
/**
 * @ClassName Squence
 * @Description TODO
 * @Author ouyangkang
 * @Date 2019-03-12 14:24
 **/
public class Squence {

    private Object[] items;

    private int next;

    public Squence(int size) {
        items = new Object[size];
    }

    public void add(Object x) {
        if (next < items.length) {
            items[next++] = x;
        }
    }

    private class SequceneSelector implements Selector {

        private int i;

        @Override
        public boolean end() {
            return i == items.length;
        }

        @Override
        public Object current() {
            return items[i];
        }

        @Override
        public void next() {
            if (i < items.length) {
                i++;
            }
        }
    }

    public Selector selector(){
        return new SequceneSelector();
    }
}

class Test{
    public static void main(String[] args) {
        Squence squence = new Squence(10);
        for (int i = 0; i < 10 ; i++) {
            squence.add(i);
        }
        // 調用內部類  這是迭代器模式的一個例子。 通過內部類 ,訪問類中的私有屬性。
        Selector selector = squence.selector();
        while (!selector.end()){
            System.out.print(selector.current()+" ");
            selector.next();
        }
    }
}

輸出: 0 1 2 3 4 5 6 7 8 9

請仔細查看上面代碼。 這是個非常好的例子。訪問權限為 private 的內部類 SequceneSelector 實現了 Selector 接口 ,該內部類可以訪問外部類 Squence 中私有屬性 items 。 並提供一個公開的方法 selector ,返回一個,向上轉型為 Selector 類型。 在測試代碼中。先創建 squence 對象。 往里面添加10個元素。 並調用該對象的中的 selector() 方法,返回一個 Selector 類型的對象。 根據我們定義的 Selector 接口中方法的含義,編碼。打印輸出。

上面代碼說明了內部類的幾個好處:

  1. 隱藏了細節,實現一個接口,向上轉型。
  2. 可以訪問外部類中的所有私有屬性,方法。就像是擁有他們一樣。但是不是擁有(你可以把它想成一個成員方法)

我覺得第一點沒什么好說的,反倒是第二點,自己是這樣理解的:外部類就像是一個房子,里面的成員變量,方法,內部類。就像是房子里面的人。可以相互通信。而內部類實現了一個接口或着抽象類后,就有點像細作一樣,表面看起來是房子里面的人,其實真正是外面的人。只要我創建它,並通過向上轉型,就可以到外面去通信。

局部內部類

定義: 如果把A類定義再B類的方法中,那么把A類叫做局部內部類

代碼如下:

public class A {
    private void getB(){
    	class B{}
    }

}

其實上面代碼意義並不大。 下面看下一些有意義的代碼。代碼如下:

/**
 * @InterfaceName Destination
 * @Description TODO
 * @Author ouyangkang
 * @Date 2019-03-12 19:59
 **/
public interface Destination {
    String readLabel();
}
/**
 * @ClassName Parcel
 * @Description TODO
 * @Author ouyangkang
 * @Date 2019-03-12 20:00
 **/
public class Parcel {
    public Destination destination(String str){
        class PDestination implements Destination{

            private String label = str;

            public PDestination(String label){
                this.label = label;
            }
            @Override
            public String readLabel() {
                return label;
            }
        }
        return new PDestination(str);
    }

    public static void main(String[] args) {
        Parcel parcel = new Parcel();
        Destination destination = parcel.destination("hello");
        System.out.println(destination.readLabel());
    }
}

輸出 hello

定義一個為 Destination 的接口,方法為 readLabel() 。 Parcel 類中定義了一個 返回 Destination 類型的方法。 該方法中定義了一個 PDestination 類,並實現了 Destination 接口。 在最后返回PDestination 的對象。 上面局部內部類很熟悉把。下面,我們看下匿名內部類。

匿名內部類

將上面Parcel類修改 ,代碼如下

/**
 * @ClassName Parcel1
 * @Description TODO
 * @Author ouyangkang
 * @Date 2019-03-13 15:33
 **/
public class Parcel1 {

    public Destination destination(final String str){
        return new Destination() {
            private String label = str;
            @Override
            public String readLabel() {
                return label;
            }
        };
    }

    public static void main(String[] args) {
        Parcel1 parcel1 = new Parcel1();
        Destination ouyangkang = parcel1.destination("hello");
        System.out.println(ouyangkang.readLabel());
    }
}

輸出:hello

Parce1 中的 destination() 方法直接 new 了一個 Destination 對象,重寫該 readLabel() 方法。 這樣返回沒有名字的局部內部類類,稱為匿名內部類。

局部內部類 VS 匿名內部類

在使用局部內部類或着匿名內部類的時候,要使用外部類中的局部變量是,該變量要為final ,要問為為什么,因為局部內部類或着匿名內部類內部對局部變量操作並不會改變改內容,所以為了防止使用錯誤。就用final修飾。不可變。其根本原因就是不會有任何的變化。
那么什么時候用局部內部類,什么時候用匿名內部類?
在你需要一個已命名的構造器,或着需要重構構造器。需要的不止是該一個內部類對象。就是你要定義多個構造器的時候用局部內部類。如果不需要就用匿名內部類。
JAVA 8 可以用Lambda 表達式表示
上面 Parcel1 類 用 JAVA 8 編碼如下

public class Parcel2 {

    public Destination destination(final String str) {
        return ()->{
            String label = str;
            return label;
        };
    }

    public static void main(String[] args) {
        Parcel2 parcel2 = new Parcel2();
        Destination ouyangkang = parcel2.destination("hello");
        System.out.println(ouyangkang.readLabel());
    }

   
}

輸出:hello

嵌套類

如果把A類定義在B類中,並A類用static關鍵字修飾,那么把A叫做嵌套類。
代碼如下:

publc class B{
	static class A{}
}

如果不需要內部類和外部類有關系,就把該內部類聲明為 static
創建嵌套類代表:

  1. 並不需要外圍類對象
  2. 不能從嵌套類的對象中訪問外部類中的 非靜態的東西。

我一般用嵌套類來做測試類。嵌套類理解就到此為止了

總結

總的來說,Java 中的 內部類並沒有想象的的那么難理解和認知,但是內部類使用起來就比較深奧了,其中多態這一特性在,配合着內部類,可謂說賊強了。隱藏細節,關注接口中方法本身的意思。


免責聲明!

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



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