首頁  >  文章  >  Java  >  內部類別和匿名內部類別的用法

內部類別和匿名內部類別的用法

高洛峰
高洛峰原創
2016-12-15 13:15:182838瀏覽

一、內部類別: 

(1)內部類別的同名方法

內部類別可以呼叫外層類別的方法,如果內部類別有同名方法必須使用"OuterClass.this.MethodName()"格式呼叫(其中OuterClass與MethodName換成實際外部類別名稱及其方法;this為關鍵字,表示外部類別的參考);若內部類別無同名方法可以直接呼叫外圍類別的方法。
但外圍類別無法直接呼叫內部類別的private方法,外部類別同樣無法直接呼叫其它類別的private方法。注意:內部類別直接使用外部類別的方法與該方法的權限與是否static無關,它取決於內部類別是否有同名方法。

package innerclass;
public class OuterClass {
    private void outerMethod() {
        System.out.println("It's Method of OuterClass");
    }
    public static void main(String[] args) {
        OuterClass t = new OuterClass();
        OuterClass.Innerclass in = t.new Innerclass();
        in.innerMethod();
    }
 
    class Innerclass {
        public void innerMethod() {
           OuterClass.this.outerMethod();// 内部类成员方法与外部类成员方法同名时,使用this调用外部类的方法
           outerMethod();// 内部类没有同名方法时执行外部类的方法
        }
        private void outerMethod() {
            System.out.println("It's Method of Innerclass");
        }
    }
}

輸出結果為:

It's Method of OuterClass
It's Method of Innerclass

(2)內部類別的實例化

內部類別實例化不同於普通類,普通類別可以在任意需要的時候實例化,而內部類別必須在外層類別實例化以後方可實例化,並與外部類別建立關係

因此在外部類別中的非static方法中,是可以實例化內部類別物件

private void outerMethod() {
    System.out.println("It's Method of OuterClass");
    Innerclass in = new Innerclass();//在外部类的outerMethod方法中实例化内部类是可以啊
}

但在static方法中,就要注意! ! ! !不能在static方法中直接new內部類,否則出現錯誤:

 

No enclosing instance of type OuterClass is accessible. Must qualify the allocation with an enclosing instance of type OuterClass (e.g. x. A(insta) wh: new instance. OuterClass).

這是因為靜態方法是在類別實例化之前就可以使用的,透過類別名稱調用,這時動態內部類別都還沒實例化呢,怎麼用,總不能調用一個不存在的東西吧。

如果想在Static方法中new內部類,可以把內部類別宣告為Static

public class OuterClass {
    private void outerMethod() {
        System.out.println("It's Method of OuterClass");
    }
 
    public static void main(String[] args) {
        Innerclass in = new Innerclass();
        in.innerMethod();
    }
 
    static class Innerclass {//把内部类声明为static
        public void innerMethod() {
            System.out.println("It's Method of innerMethod");
 
        }
    }
 
}

當然,一般不使用static的方式,而是推薦這種方法:x.new A() ,其中x是外部類OuterClass的實例,A是內部類別Innerclass

package innerclass;
public class OuterClass {
    private void outerMethod() {
        System.out.println("It's Method of OuterClass");
    }
    public static void main(String[] args) {
        OuterClass.Innerclass in = new OuterClass().new Innerclass();//使用x.new A()的方式
        in.innerMethod();
    }
    class Innerclass {
        public void innerMethod() {
            System.out.println("It's Method of innerMethod");
        }
    }
}

x.new A() ,其中x是外部類別OuterClass的實例,A是類別部類別Innerclass,當然可以分割如下,這樣就顯然很明白:

public static void main(String[] args) {
    OuterClass out = new OuterClass();//外部实例
    OuterClass.Innerclass in = out.new Innerclass();//外部实例.new 外部类
    in.innerMethod();
}

(3)什麼情況下使用內部類別
典型的情況是,內部類別繼承自某個類別或實作某個接口,內部類別的程式碼操作建立其的外層類別的物件。所以你可以認為內部類別提供了某種進
入其外層類別的視窗。
使用內部類別最吸引人的原因是:每個內部類別都能獨立地繼承自一個(介面的)實現,所以無論外層類別是否已經繼承了某個(介面的)實
現,對於內部類別都沒有影響。如果沒有內部類別提供的可以繼承多個具體的或抽象的類別的能力,一些設計與程式設計問題就很難解決。從這個角
度看,內部類別使得多重繼承的解決方案變得完整。介面解決了部分問題,而內部類別有效地實現了「多重繼承」。

(4)在靜態方法中實例化內部類別範例:(內部類別放在靜態方法中)

package javatest2;
public class JavaTest2 {
    public static void main(String[] args) {
        class Boy implements Person {
            public void say() {// 匿名内部类自定义的方法say
                System.out.println("say方法调用");
            }
            @Override
            public void speak() {// 实现接口的的方法speak
                System.out.println("speak方法调用");
            }
        }
        Person per = new Boy();
        per.speak();// 可调用
        per.say();// 不能调用
    }
}
interface Person {
    public void speak();
}

per.speak()可調用,而per.say()不能調用,這時因為per是Person對象,要呼叫子類別的方法,可以強制向下轉型為:((Boy) per).say();或直接改為Boy per = new Boy();。從中可發現,若要呼叫內部類別的自訂的方法,必須透過內部類別的物件來呼叫。那麼,匿名內部類別連名字都沒有,怎麼呼叫內部類別自訂的方法呢?

 

(二)匿名內部類別

匿名內部類別也就是沒有名字的內部類別正因為沒有名字,所以匿名內部類別只能使用一次,它通常用來簡化程式碼編寫,但使用匿名內部類別還有個前提條件:必須繼承一個父類或實作一個接口,但最多只能繼承一個父類,或實作一個接口。
關於匿名內部類別還有以下兩條規則:
1)匿名內部類別不能是抽象類別,因為系統在建立匿名內部類別的時候,會立即建立內部類別的物件。因此不允許將匿名內部類別定義成抽象類別。
2)匿名內部類別不等定義建構器(建構方法),因為匿名內部類別沒有類別名,所以無法定義建構器,但匿名內部類別可以定義實例初始化區塊,

怎麼判斷一個匿名類別的存在啊?看不見名字,感覺只是父類別new出一個物件而已,沒有匿名類別的名字。
先看段偽代碼

abstract class Father(){
....
}
public class Test{
   Father f1 = new Father(){ .... }  //这里就是有个匿名内部类
}

一般來說,new 一個物件時小括號後應該是分號,也就是new出物件該語句就結束了。但出現匿名內部類別就不一樣,小括號後面接的是大括號,大括號中是該new 出物件的具體的實作方法。因為我們知道,一個抽象類別是不能直接new 的,必須先有實作類別了我們才能new出它的實作類別。上面的偽代碼就是表示new 的是Father的實作類,這個實作類別是個匿名內部類別。
其實拆分上面的匿名內部類別可為:

class SonOne extends Father{
  ...       //这里的代码和上面匿名内部类,大括号中的代码是一样的
}
public class Test{
   Father f1 = new SonOne() ;
}

先看一個例子,體會一下匿名內部類別的用法:

內部類別和匿名內部類別的用法

运行结果:eat something
可以看到,我们直接将抽象类Person中的方法在大括号中实现了,这样便可以省略一个类的书写。并且,匿名内部类还能用于接口上

public class JavaTest2 {
    public static void main(String[] args) {
        Person per = new Person() {
            public void say() {// 匿名内部类自定义的方法say
                System.out.println("say方法调用");
            }
            @Override
            public void speak() {// 实现接口的的方法speak
                System.out.println("speak方法调用");
            }
        };
        per.speak();// 可调用
        per.say();// 出错,不能调用
    }
}
 
interface Person {
    public void speak();
}

这里per.speak()是可以正常调用的,但per.say()不能调用,为什么呢?注意Person per = new Person()创建的是Person的对象,而非匿名内部类的对象。其实匿名内部类连名字都没有,你咋实例对象去调用它的方法呢?但继承父类的方法和实现的方法是可以正常调用的,本例子中,匿名内部类实现了接口Person的speak方法,因此可以借助Person的对象去调用。

 

若你确实想调用匿名内部类的自定义的方法say(),当然也有方法:

(1)类似于speak方法的使用,先在Person接口中声明say()方法,再在匿名内部类中覆写此方法。

(2)其实匿名内部类中隐含一个匿名对象,通过该方法可以直接调用say()和speak()方法;代码修改如下:

public class JavaTest2 {
    public static void main(String[] args) {
        new Person() {
            public void say() {// 匿名内部类自定义的方法say
                System.out.println("say方法调用");
            }
 
            @Override
            public void speak() {// 实现接口的的方法speak
                System.out.println("speak方法调用");
            }
        }.say();// 直接调用匿名内部类的方法
    }
}
interface Person {
    public void speak();
}


更多内部类和匿名内部类的用法相关文章请关注PHP中文网!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn