7. java 內部類

基本概念

能夠將一個類定義在另外一個類裏面或者一個方法裏面,這樣的類稱爲內部類。java

普遍意義上的內部類通常來講包括這四種:函數

  • 成員內部類
  • 局部內部類
  • 靜態內部類
  • 匿名內部類

成員內部類

成員內部類是最普通的內部類,它的定義爲位於另外一個類的內部,形以下面的形式:測試

public class testDemo {
    public static void main(String[] args ) {
        Outer t = new Outer();
        Outer.Inner in = t.new Inner(); // 必須先有外部類對象,才能建立內部類
        t.fun();
        in.print();
    }
}

class Outer { //外部類
    private String msg = "hello world";
    
    public void fun(){
       Inner in =  new Inner();
       System.out.println(in.info); //外部類直接訪問內部類的私有屬性
    }

    class Inner{ //定義了一個成員內部類
        private String info = "世界,你好!";
        public void print(){
            System.out.println(msg); //內部類直接訪問外部類的private屬性
        }
    }

}

成員內部類能夠無條件訪問外部類的全部屬性和方法(包括private成員和靜態成員)。外部類也能夠直接訪問內部類的全部屬性和方法。this

成員內部類是依附外部類而存在的,也就是說,若是要建立成員內部類的對象,前提是必須存在一個外部類的對象設計

在外部類中若是要訪問成員內部類的成員,必須先建立一個成員內部類的對象,再經過指向這個對象的引用來訪問。code

不過要注意的是,當成員內部類擁有和外部類同名的成員變量或者方法時,會發生隱藏現象,即默認狀況下訪問的是成員內部類的成員。若是要訪問外部類的同名成員,須要如下面的形式進行訪問:對象

外部類.this.成員變量
外部類.this.成員方法

局部內部類

局部內部類是定義在一個方法或者一個做用域裏面的類,它和成員內部類的區別在於局部內部類的做用域僅限於方法內或者該做用域內。繼承

public class testDemo {
    public static void main(String[] args ) {
      new Outer().fun();
    }
}
class Outer { //外部類
    private String msg = "hello world";
    public void fun(){
        class Inner{ //在方法中定義了一個局部內部類
            public void print(){
                System.out.println(Outer.this.msg); //直接訪問外部類的private屬性
            }
        }
        new Inner().print();
    }
}

注意:局部內部類就像是方法裏面的一個局部變量同樣。接口

在jdk1.7或以前的版本,若是局部內部類要訪問方法中定義的參數、局部變量,那麼參數和變量前必定要加上"final"修飾符。jdk1.8以及更新的版本則沒有這個限制。作用域

public class testDemo {
    public static void main(String[] args ) {
      new Outer().fun(100);
    }
}

class Outer { //外部類

    private String msg = "hello world";

    public void fun(final int num){
        final double score = 99.9; 
        class Inner{ //在方法中定義了一個局部內部類
            public void print(){
                System.out.println("屬性:"+Outer.this.msg); //直接訪問外部類的private屬性
                System.out.println("方法參數"+ num);
                System.out.println("方法局部變量"+ score);
            }
        }
        new Inner().print();
    }

}

靜態內部類

使用static修飾的成員內部類叫靜態內部類。靜態內部類是不須要依賴於外部類的,這點和類的靜態成員屬性有點相似,而且它不能訪問外部類的非static成員變量或者方法。

public class testDemo {
    public static void main(String[] args ) {
        Outer.Inner in = new Outer.Inner(); //靜態內部類可使用"外部類.內部類"的方式使用
        in.print();
    }
}

class Outer { //外部類
    
    static class Inner{ //定義了一個靜態內部類
        private String info = "世界,你好!";
        public void print(){
            System.out.println(info);
        }
    }

}

匿名內部類

當某個子類只使用惟一一次的時候,沒有必要單獨定義出來,可使用匿名內部類的方法簡化代碼。

匿名內部類就是沒有名字的局部內部類。建立格式以下:

new 父類構造器(參數列表)| 要實現的接口 () {  
     //匿名內部類的類體部分 
     //....
}

匿名內部類是在抽象類和接口的基礎上發展而來的,其最大的好處是幫助減小了類的定義。

在使用匿名內部類的過程當中,咱們須要注意以下幾點:

  • 使用匿名內部類時,咱們必須是繼承一個類或者實現一個接口,可是二者不可兼得,同時也只能繼承一個類或者實現一個接口。
  • 匿名內部類中是不能定義構造函數的。
  • 匿名內部類中不能存在任何的靜態成員變量和靜態方法。
  • 匿名內部類爲局部內部類,因此局部內部類的全部限制一樣對匿名內部類生效。
  • 匿名內部類不能是抽象的,它必需要實現繼承的類或者實現的接口的全部抽象方法。
  • 當所在的方法的形參須要被內部類裏面使用時,該形參必須爲final(jdk1.8以後可省略)。

示例:

//接口
 interface Inner {
    public String say();
}
//抽象類
 abstract class Inner1 implements Inner{

}
//普通類
class Inner2 implements Inner{
    public String say(){
        return "this is Inner2";
    }
}

class Outer {
    public void method1(Inner inner) {
        System.out.println(inner.say());
    }
}

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

        Outer outer = new Outer();
        // 測試1,Inner爲接口
        outer.method1(new Inner() {
            String s1 = "this is s1 in Inner";

            public String say() {
                // 外部類和匿名函數類中有同名變量s1
                return s1;
            }
        });

        // 測試2,Inner1爲抽象類
        outer.method1(new Inner1() {
            String s2 = "this is s2 in Inner1";

            public String say() {
                // 外部類和匿名函數類中有同名變量s2
                return s2;
            }
        });

        //測試3, Inner2爲普通類
        outer.method1(new Inner2() {
            public String say() {
                return "this is inner2 overrite";
            }
        });

    }
}
輸出結果:
this is s1 in Inner
this is s2 in Inner1
this is inner2 overrite

內部類的做用

爲何要使用內部類?在《Think in java》中有這樣一句話:使用內部類最吸引人的緣由是:每一個內部類都能獨立地繼承一個(接口的)實現,因此不管外圍類是否已經繼承了某個(接口的)實現,對於內部類都沒有影響。

在咱們程序設計中有時候會存在一些使用接口很難解決的問題,這個時候咱們能夠利用內部類提供的、能夠繼承多個具體的或者抽象的類的能力來解決這些程序設計問題。能夠這樣說,接口只是解決了部分問題,而內部類使得多重繼承的解決方案變得更加完整。內部類最大的優勢就在於它可以很是好的解決多重繼承的問題.

內部類還可以爲咱們帶來以下特性:

  1. 內部類能夠用多個實例,每一個實例都有本身的狀態信息,而且與其餘外圍對象的信息相互獨立。
  2. 在單個外圍類中,可讓多個內部類以不一樣的方式實現同一個接口,或者繼承同一個類。
  3. 建立內部類對象的時刻並不依賴於外圍類對象的建立。
  4. 內部類並無使人迷惑的「is-a」關係,他就是一個獨立的實體。
相關文章
相關標籤/搜索