Java 中的內部類

前言

在第一次把Java 編程思想中的內部類這一章擼完後,有點印象。大概知道了什麼時內部類,局部內部類,匿名內部類,嵌套內部類。隨着時間的推移,本身慢慢的就忘記了,總感受本身思考的東西很少,因而 看了第二遍,並把本身的想法和一些筆記寫下來。供之後參考。java

內部類

定義:若是把A類定義再B類裏面,那麼把A類叫作 內部類編程

代碼以下:ide

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 9this

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

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

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

我以爲第一點沒什麼好說的,反卻是第二點,本身是這樣理解的:外部類就像是一個房子,裏面的成員變量,方法,內部類。就像是房子裏面的人。能夠相互通訊。而內部類實現了一個接口或着抽象類後,就有點像細做同樣,表面看起來是房子裏面的人,其實真正是外面的人。只要我建立它,並經過向上轉型,就能夠到外面去通訊。code

局部內部類

定義: 若是把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 中的 內部類並無想象的的那麼難理解和認知,可是內部類使用起來就比較深奧了,其中多態這一特性在,配合着內部類,可謂說賊強了。隱藏細節,關注接口中方法自己的意思。

相關文章
相關標籤/搜索