天天看點

[Java開發之路](24)内部類

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。 https://blog.csdn.net/SunnyYoona/article/details/51055804

在Java中,可以将一個類定義在另一個類裡面或者一個方法裡面,這樣的類稱為内部類。廣泛意義上的内部類一般來說包括這四種:成員内部類、局部内部類、匿名内部類和靜态内部類。下面就先來了解一下這四種内部類的用法。

1. 成員内部類

成員内部類是定義在另一個類内部的類。

  1. package com.qunar.fresh;

  2. /**

  3. * Created by xiaosi on 16-3-29.

  4. */

  5. public class Circle {

  6.    private double radius;

  7.    public Circle(double radius) {

  8.        this.radius = radius;

  9.    }

  10.    // 内部類

  11.    class Draw{

  12.        public void drawCircle(){

  13.            System.out.println("Circle---->" + radius);

  14.        }

  15.    }

  16.    public Draw getDrawInstance(){

  17.        return new Draw();

  18.    }

  19.    public static void main(String[] args) {

  20.        Circle circle = new Circle(12.5);

  21.        circle.getDrawInstance().drawCircle(); // 12.5

  22.    }

  23. }

Circle稱為外部類。成員内部類可以無條件通路外部類的所有成員屬性和成員方法(包括private成員和靜态成員)。在内部類drawCircle方法中,可以很輕松的通路外部類的私有成員radius。

注意點:

(1)當成員内部類擁有和外部類同名的成員變量或者方法時,會發生隐藏現象,即預設情況下通路的是成員内部類的成員。

  1. public class Circle {

  2.    private double radius;

  3.    public Circle(double radius) {

  4.        this.radius = radius;

  5.    }

  6.    // 内部類

  7.    class Draw {

  8.        private double radius;

  9.        public Draw(double radius) {

  10.            this.radius = radius;

  11.        }

  12.        public void drawCircle() {

  13.            // 成員内部類擁有和外部類同名的成員變量或者方法時,預設情況下通路的是成員内部類的成員

  14.            System.out.println("Circle---->" + radius);

  15.        }

  16.    }

  17.    public Draw getDrawInstance(double radius) {

  18.        return new Draw(radius);

  19.    }

  20.    public static void main(String[] args) {

  21.        Circle circle = new Circle(12.5);

  22.        circle.getDrawInstance(11.6).drawCircle(); // 11.6

  23.    }

  24. }

如果要通路外部類的同名成員,需要以下面的形式進行通路:

  • 外部類.this.成員變量
  • 外部類.this.成員方法
  1. public void drawCircle() {

  2.    System.out.println("Circle---->" + Circle.this.radius); // 12.5

  3. }

(2)成員内部類可以無條件地通路外部類的成員,而外部類通路成員内部類的成員卻這麼簡單。在外部類中通路成員内部類的成員,必須先建立一個成員内部類的對象,再通過指向這個對象的引用來通路:

  1. public class Circle {

  2.    private double radius;

  3.    public Circle(double radius) {

  4.        this.radius = radius;

  5.        // 需要建立成員内部類的對象

  6.        new Draw().drawCircle();

  7.    }

  8.    // 成員内部類

  9.    class Draw {

  10.        public void drawCircle() {

  11.            System.out.println("Circle---->" + radius); // 12.5

  12.        }

  13.    }

  14.    public static void main(String[] args) {

  15.        Circle circle = new Circle(12.5); // Circle---->12.5

  16.    }

  17. }

(3)成員内部類是依附外部類而存在的,也就是說,如果要建立成員内部類的對象,前提是必須存在一個外部類的對象。建立成員内部類對象的一般方式如下:

  1. package com.qunar.fresh;

  2. /**

  3. * Created by xiaosi on 16-3-29.

  4. */

  5. public class Outer {

  6.    private String name;

  7.    public Outer(String name) {

  8.        this.name = name;

  9.    }

  10.    // 成員内部類

  11.    class Inner {

  12.        public void print() {

  13.            System.out.println("Outer---->" + name); // Outer---->OuterClass

  14.        }

  15.    }

  16.    public static void main(String[] args) {

  17.        Outer outer = new Outer("OuterClass");

  18.        Outer.Inner inner = outer.new Inner();

  19.        inner.print();

  20.    }

  21. }

第2種方式:

  1. package com.qunar.fresh;

  2. /**

  3. * Created by xiaosi on 16-3-29.

  4. */

  5. public class Outer {

  6.    private String name;

  7.    private Inner inner = null;

  8.    public Outer(String name) {

  9.        this.name = name;

  10.    }

  11.    public Inner getInstance() {

  12.        if (inner == null) {

  13.            return new Inner();

  14.        }

  15.        return inner;

  16.    }

  17.    // 成員内部類

  18.    class Inner {

  19.        public void print() {

  20.            System.out.println("Outer---->" + name); // Outer---->OuterClass

  21.        }

  22.    }

  23.    public static void main(String[] args) {

  24.        Outer outer = new Outer("OuterClass");

  25.        Outer.Inner inner = outer.getInstance();

  26.        inner.print();

  27.    }

  28. }

(4)内部類可以擁有private、protected、public及包通路權限。比如上面的例子,如果成員内部類Inner用private修飾,則隻能在外部類的内部通路,如果用public修飾,則任何地方都能通路;如果用protected修飾,則隻能在同一個包下或者繼承外部類的情況下通路;如果是預設通路權限,則隻能在同一個包下通路。這一點和外部類有一點不一樣,外部類隻能被public和包通路兩種權限修飾。

2. 局部内部類

局部内部類是定義在一個方法或者一個作用域内的類,它和成員内部類的差別在于局部内部類的通路僅限于方法内或者該作用域内。

備注:

局部内部類就像是方法裡面的一個局部變量一樣,是不能有public、protected、private以及static修飾符的。

3. 匿名内部類

匿名類是不能有名稱的類,是以沒辦法引用它們。必須在建立時,作為new語句的一部分來聲明它們。這就要采用另一種形式的new語句,如下所示: new <類或接口> <類的主體> 這種形式的new語句聲明一個新的匿名類,它對一個給定的類進行擴充,或者實作一個給定的接口。它還建立那個類的一個新執行個體,并把它作為語句的結果而傳回。

舉個例子來說,假設你有一個Map,key是物品,value是對應的價格,機關是人民币。現在有個需求是将裡面的價格都轉換為美元,傳統的做法是周遊整個Map,然後更新每個value值,将價格轉換為美元價格,這種方式比較麻煩。我們使用Function可以解決這一問題。

  1. @Test

  2.    public void test1(){

  3.        Map<String,Double> map = Maps.newHashMap();

  4.        map.put("apple",4.5);

  5.        map.put("bear",6.3);

  6.        // {bear=6.3, apple=4.5}

  7.        System.out.println(map.toString());

  8.        Map<String,Double> newMap = Maps.transformValues(map, new Function<Double, Double>() {

  9.            double rate = 0.1544;

  10.            @Override

  11.            // 轉換為美元

  12.            public Double apply(Double input) {

  13.                return rate * input;

  14.            }

  15.        });

  16.        // {bear=0.97272, apple=0.6948000000000001}

  17.        System.out.println(newMap.toString());

  18.    }

new Function<Double,Double>(){...}就是建立一個内部類。

匿名内部類是唯一一種沒有構造器的類(不能定義構造器)。正因為其沒有構造器,是以匿名内部類的使用範圍非常有限,大部分匿名内部類用于接口回調。匿名内部類在編譯的時候由系統自動起名為Outter$1.class。一般來說,匿名内部類用于繼承其他類或是實作接口,并不需要增加額外的方法,隻是對繼承方法的重寫或者對接口方法的實作。

匿名内部類不能是抽象類,因為系統在建立匿名内部類的時候,會立即建立内部類的對象。是以不允許将匿名内部類定義成抽象類。

4. 靜态内部類

靜态内部類也是定義在另一個類裡面的類,隻不過在類的前面多了一個關鍵字static。靜态内部類是不需要依賴于外部類的,這點和類的靜态成員屬性有點類似,并且它不能使用外部類的非static成員變量或者方法,因為在沒有外部類的對象的情況下,可以建立靜态内部類的對象,如果允許通路外部類的非static成員就會産生沖突,因為外部類的非static成員必須依附于具體的對象。

  1. public class Outer2 {

  2.    private static String sname = "Outer2";

  3.    private String name;

  4.    public Outer2(String name) {

  5.        this.name = name;

  6.    }

  7.    // 成員内部類

  8.    public static class Inner {

  9.        public void print() {

  10.            // 靜态内部類不能通路外部類的非static成員變量或者方法

  11.            // System.out.println("Outer---->" + name);

  12.            // 可以使用靜态變量或者方法

  13.            System.out.println("Outer---->" + sname);

  14.        }

  15.    }

  16. }

調用:

  1. Outer2.Inner inner2 = new Outer2.Inner();

  2. inner2.print();