定義在類內(nèi)部的類就稱之為內(nèi)部類。根據(jù)定義的不同可以分為成員內(nèi)部類,局部內(nèi)部類,匿名類,靜態(tài)內(nèi)部類。無論是哪一種內(nèi)部類,我們都可以在內(nèi)部類中直接存取外部類的私有成員變量。(私有成員屬性&私有成員方法,因為內(nèi)部類持有外部類的引用)
為什么要引入內(nèi)部類
1.為了更好的封裝,將內(nèi)部類封裝在外部類內(nèi),可以方便地訪問外部類成員變量,同時,將其與其他類進行隔離,不允許同包其他類訪問。
2.內(nèi)部類的屬性和方法即便是外部類也不能隨意地訪問。(可以通過在外部類實例化內(nèi)部類進行訪問,即使該變量是private類型)
3.有利于回調(diào)函數(shù)的編寫。
3.當面向?qū)ο髸r,有利于我們對整體和成員的封裝。
成員內(nèi)部類
成員內(nèi)部類的語法如下:
public class OuterClass {
private class Inner {
//...
}
}
成員內(nèi)部類的特性除了最開始提到的可以存取所在外部類的所有成員變量之外,成員內(nèi)部類的實例必須綁定在外部類的實例上,如果我們在外部類中初始化了一個內(nèi)部類對象,那么內(nèi)部類對象就會綁定在外部類對象上。
舉例說明:
public class OuterClass {
InnerClass inner = new InnerClass(); //外部類中實例化內(nèi)部類
private int a = 0;
private void take() {
a = inner.x;
a = inner.y;
//x = 1; //錯誤,外部類不能直接訪問內(nèi)部類變量
inner.hello();
inner.hi();
}
public InnerClass getInner() { //在外部類方法中返回內(nèi)部類引用
return new InnerClass();
}
class InnerClass {
public int x = 0; //內(nèi)部類公有屬性
private int y = 0; //內(nèi)部類私有屬性
public void hello() {
x = a; //內(nèi)部類可以直接訪問外部類成員變量
}
private void hi() {
take();
}
}
}
從上面的例子我們可以得知,內(nèi)部類可以隨意訪問所在外部類的成員,而內(nèi)部類的成員只有在內(nèi)部類的范圍內(nèi)是可知的,不能被外部類使用,比如例子中對內(nèi)部類的成員屬性進行賦值將會報錯,但是我們可以通過內(nèi)部類對象引用成員變量。
OuterClass outerClass = new OuterClass();
//內(nèi)部類的實例化只能在外部類或外部類的非靜態(tài)方法中實現(xiàn)
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
OuterClass.InnerClass innerClass1 = outerClass.getInner();
另外,在上面的例子中,如果不使用getInner()方法返回內(nèi)部類對象引用,可以直接使用內(nèi)部類實例化內(nèi)部類對象,但是由于在主方法中來實例化內(nèi)部類對象,必須在new操作符之前提供一個外部類的引用。
Question
1.為什么外部類可以通過實例化內(nèi)部類直接訪問內(nèi)部類的private成員?
首先,我們得了解訪問權限(Accessibility)如何規(guī)定的?
官方定義:
If the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class that encloses the declaration of the member or constructor.
從此我們可以了解到,如果一個類的成員被聲明為private類型的,那么在它的頂級類(top level class)的范圍內(nèi)是可以訪問的。那么它又是怎么實現(xiàn)的呢?
2.為什么只有內(nèi)部類可以被聲明為private或protected訪問類型?
對于頂級類而言,只能聲明為public訪問權限類型或者缺省類型,public類型表示對所有類可見,缺省類型則為包級訪問權限,對同一個package下的類可見。如果一個頂級類被聲明為private類型,那么它對于其他類都是不可見的,這樣類就毫無意義。說到這,順便復習下類成員的訪問權限,如果一個類的成員被修飾為private,則該成員只能在該類內(nèi)部使用,在子類中是不可見的,并且對其他包的類也是不可見的。如果一個類的成員被修飾為public,那么除了可以在本類使用使用之外,還可以在子類和其他包的類中使用。如果一個類使用protected修飾符,那么只有本包內(nèi)的子類或其他類可以訪問此類中的成員。
Attention:類的權限設定會約束類成員的權限設定。
局部內(nèi)部類
內(nèi)部類不僅可以在類中定義,還可以在類的局部位置定義,如在類的方法或任意的作用域均可以定義內(nèi)部類。
舉例說明:
public class OuterClass {
public void take() {
class InnerClass {
//do something
}
}
}
Attention:局部內(nèi)部類InnerClass是方法take()的一部分,不是外部類OuterClass的一部分,所以在take()的外部不能訪問該內(nèi)部類,而InnerClass可以訪問當前代碼塊的成員以及外部類的所有成員。
匿名內(nèi)部類
舉例說明:
public class OuterClass {
public MyInterface handle() {
return new MyInterface() {
@Override
public void take() {
//do something
}
};
}
}
在handle()方法中,我們通過return后面插入一個定義內(nèi)部類的代碼,返回一個MyInterface接口的引用,由于這個類沒有名稱,所以將之稱為匿名內(nèi)部類。
靜態(tài)內(nèi)部類
在內(nèi)部類前面添加static修飾符,這個內(nèi)部類就變成了靜態(tài)內(nèi)部類,一個靜態(tài)內(nèi)部類中可以聲明靜態(tài)成員,在非靜態(tài)內(nèi)部類中不可以聲明靜態(tài)成員。靜態(tài)內(nèi)部類有一個最大的特點就是不可以使用外部類的非靜態(tài)成員。當然,如果創(chuàng)建靜態(tài)內(nèi)部類的對象,不需要其外部類的對象。
public class OuterClass {
private int x = 0;
private static int y = 0;
static class InnerClass {
void handle() {
//System.out.println(x); //wrong
System.out.println(y); //right
}
}
}