1. 程式人生 > >內部類、匿名內部類、內部介面比較

內部類、匿名內部類、內部介面比較

目錄

一、什麼是內部介面?

內部介面也稱為巢狀介面,即在一個介面內部定義另一個介面,Entry介面定義在Map接口裡面,如下程式碼:

public interface Map{
    interface Entry{
        int getKey();
    }
    void clear();
}

在Java標準庫中使用內部介面的一個例子就是java.util.Map和java.util.Map.Entry.

二、在說明內部介面之前先說一下什麼是內部類?

內部類顧名思義就是在一個類的內部還有一個類
Java程式碼:

class Outer{
    private
String name = "Hello World"; class Inner{ public void print(){ System.out.println("name="+name); } } public void fun(){ new Inner().print(); } } public class TestInnerClass01{ public static void main(String args[]){ new Outer().fun(); } }

內部類的生成的.class檔名為:Outer$Inner.class,從上面的結構發現內部類的缺點是“結構非常混亂”。
Java程式碼:

class Outer{
    private String name = "Hello World";
    class Inner{
        private Outer out;
    public Inner(Outer out){
        this.out = out;
    }
    public void print(){
        System.out.println("name="+this.getName());
    }
    }
    public
String getName(){ return this.name; } public void fun(){ new Inner(this).print(); } } public class TestInnerClass02{ public static void main(String[] args){ new Outer().fun(); } }

可以看出內部類的優點是:“可以方便的訪問外部類中的私有成員”;
如果要在外部類直接使用內部類的例項化物件:
外部類.內部類 內部類物件 = 外部類例項.new 內部類例項();
Java程式碼:

class Outer{
    private String name = "Hello World";
    class Inner{
        public void print(){
        System.out.println("name="+name);
    }
    }
}
public class TestInnerClass03{
    public static void main(String[] args){
        Outer out = new Outer(); //外部類例項
    Outer.Inner inner = out.new Inner();//例項化內部類物件
    inner.print();
    }
}

一個內部類如果使用static宣告的話,則此內部類變為外部類,可以直接通過外部類.內部類的形式訪問
Java程式碼:

class Outer{
    private static String name = "Hello WOrld";
    static class Inner{
        public void print(){
        System.out.println("name="+name);
    }
    }
}
public class TestInnerClass04{
    public static void main(String[] args){
        Outer.Inner inner = new Outer.Inner()//例項化內部類物件
    inner.print();
    }
}

區域性內部類(定義在方法中的內部類)“不能用public或者private宣告”,它的作用域僅限於方法內部。
區域性內部類的優勢,即對外部世界可以完全隱藏起來。除了該方法之外,沒有任何方法知道它的存在。
在方法中定義的內部類,可以直接訪問外部類中的各個成員,但是如果要訪問方法中的引數,則需要在引數上加final關鍵字宣告。
Java程式碼:

public class TestInnerClass{
    public static void main(String[] args){
        new Outer().fun(20);
    }
}
class Outer{
    private static String name = "hello world";
    public void fun(final int temp){
        class Inner{
        public void print(){
            System.out.println("temp="+temp);
        System.out.println("name="+name);
        }
    }
    new Inner().print();
    }
}

三、成員內部類的繼承問題(易錯地方)

1、成員內部類的引用方式必須為 Outter.Inner.

2、構造器中必須有指向外部類物件的引用,並通過這個引用呼叫super()。

Java程式碼:

class WithInner {
    class Inner{

    }
}
class InheritInner extends WithInner.Inner {

    // InheritInner() 是不能通過編譯的,一定要加上形參
    InheritInner(WithInner wi) {
        wi.super(); //必須有這句呼叫
    }
    public static void main(String[] args) {
        WithInner wi = new WithInner();
        InheritInner obj = new InheritInner(wi);
    }
}

四、再說一下什麼是匿名內部類?

簡單的說匿名內部類就是沒有名字的內部類,匿名內部類只能使用一次。
使用匿名內部類的前提條件:“必須繼承一個父類或者實現一個介面”。
Java程式碼:不使用匿名內部類來實現抽象方法

abstract class Person {
    public abstract void eat();
}
class Child extends Person {
    public void eat() {
        System.out.println("eat something");
    }
}
public class TestInnerClass {
    public static void main(String[] args) {
        Person p = new Child();
        p.eat();
    }
}

可以看到,我們用Child繼承了Person類,然後實現了Child的一個例項,將其向上轉型為Person類的引用,但是,如果此處的Child類只使用一次,那麼將其編寫為獨立的一個類豈不是很麻煩?這個時候就引入了匿名內部類。
Java程式碼:匿名內部類的基本實現

abstract class Person {
    public abstract void eat();
}
public class TestInnerClass {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

可以看到,我們直接將抽象類Person中的方法在大括號中實現了,這樣便可以省略一個類的書寫並且,匿名內部類還能用於介面上。
Java程式碼:在介面上使用匿名內部類

interface Person {
    public void eat();
}
public class Demo {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

最常用的情況就是在多執行緒的實現上,因為要實現多執行緒必須繼承Thread類或是繼承Runnable介面
Java程式碼:Thread類的匿名內部類實現

public class TestInnerClass {
    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        t.start();
    }
}

Java程式碼:Runnable介面的匿名內部類實現

public class TestInnerClass{
    public static void main(String[] args){
        Runnable r = new Runnable(){
        public void run(){
             for(int i=0;i<4;i++){
             System.out.print(i+" ");
         }
        }
    };
    Thread t = new Thread(r);
    t.start();
    }
}

五、內部介面的例項

Map.java:

public interface Map{
    interface Entry{
        int getKey();
    }
    void clear();
}
MapImpl.java:
public class MapImpl implements Map{
    class ImplEmtry implements Map.Entry{
        public int getKey(){
        return 0;
    }
    }
    @Override
    public void clear(){
        //clear
    }
}