內部類別是指在一個外部類別的內部再定義一個類別。類別名稱不需要和資料夾相同。
內部類別分為: 成員內部類別、局部內部類別、靜態巢狀類別、匿名內部類別 。
1.成員內部類
成員內部類是最普通的內部類,它的定義為位於另一個類的內部,形如下面的形式:
class Outter { private int age = 12; class Inner { private int age = 13; public void print() { int age = 14; System.out.println("局部变量:" + age); System.out.println("内部类变量:" + this.age); System.out.println("外部类变量:" + Outter.this.age); } } } public class test1 { public static void main(String[] args) { Outter out = new Outter(); Outter.Inner in = out.new Inner(); in.print(); } }
運行結果:
局部变量:14 内部类变量:13 外部类变量:12
reee看出:成員內部類,就是作為外部類別的成員,可以直接使用外部類別的所有成員和方法,即使是private的。雖然成員內部類別可以無條件地存取外部類別的成員,而外部類別想存取成員內部類別的成員卻不是這麼隨心所欲了。在外部類別中如果要存取成員內部類別的成員,必須先建立一個成員內部類別的對象,再透過指向這個物件的參考來存取:
class Outter { private int age = 12; public Outter(int age) { this.age = age; getInInstance().print(); //必须先创建成员内部类的对象,再进行访问! } private Inner getInInstance() { return new Inner(); } class Inner { public void print() { System.out.println("内部类没同名,所以直接调用外部类成员变量:" + age); } } } public class test1 { public static void main(String[] args) { Outter out = new Outter(10); } }
運作結果:
内部类没同名,所以直接调用外部类成员变量:10
內部類別可以擁有private存取權限、protected存取權限、public存取權限及包存取權限。
例如上面的例子,如果成員內部類Inner用private修飾,則只能在外部類的內部訪問,如果用public修飾,則任何地方都能訪問;如果用protected修飾,則只能在同一個包下或繼承外部類別的情況下存取;如果是預設存取權限,則只能在同一個套件下存取。
這一點和外部類別有一點不一樣,外部類別只能被public和套件存取兩種權限修飾。
我個人是這麼理解的,由於成員內部類別看起來像是外部類別的一個成員,所以可以像類別的成員一樣擁有多種權限修飾。要注意的是,成員內部類別不能含有static的變數和方法。因為成員內部類別需要先創建了外部類,才能創建它自己的
2.局部內部類
局部內部類是定義在一個方法或者一個作用域裡面的類,它和成員內部類的區別在於內部類別的存取僅限於方法內或該作用域內。
定義在方法裡的內部類別:
class Outter { private int age = 12; public void Print(final int x) { //这里局部变量x必须设置为final类型! class Inner { public void inPrint() { System.out.println(x); System.out.println(age); } } new Inner().inPrint(); } } public class test1 { public static void main(String[] args) { Outter out = new Outter(); out.Print(10); } }
運行結果:
10 12
本例中我們將內部類別移到了外部類別的方法中,然後在外部類別的方法中再產生一個內部類別物件去呼叫內部類別方法。如果此時我們需要往外部類別的方法中傳入參數,那麼外部類別的方法形參必須使用final定義。
換句話說,在方法中定義的內部類別只能存取方法中final類型的局部變量,這是因為在方法中定義的局部變數相當於一個常數,它的生命週期超出方法運行的生命週期,由於局部變數被設定為final,所以不能再內部類別中改變局部變數的值。 (這裡看到網路上有不同的解釋,還沒有徹底搞清楚==)
定義在作用域內的內部類別:
class Outter { private int age = 12; public void Print(final boolean x) { //这里局部变量x必须设置为final类型! if(x){ class Inner { public void inPrint() { System.out.println(age); } } new Inner().inPrint(); } } } public class test1 { public static void main(String[] args) { Outter out = new Outter(); out.Print(true); } }
3.靜態巢狀類
又叫靜態局部類、巢狀內部類,就是修飾為static的內部類別。聲明為static的內部類,不需要內部類別物件和外部類別物件之間的聯繫,就是說我們可以直接引用outer.inner,也就是不需要建立外部類別,也不需要建立內部類別。
class Outter { private static int age = 12; static class Inner { public void print() { System.out.println(age); } } } public class test1 { public static void main(String[] args) { Outter.Inner in = new Outter.Inner(); in.print(); } }
可以看到,如果用static 將內部內靜態化,那麼內部類別就只能存取外部類別的靜態成員變量,具有限制。
其次,因為內部類別被靜態化,因此Outter.Inner可以當做一個整體看,可以直接new 出內部類別的物件(透過類別名稱存取static,生不產生外部類別物件都沒關係)
4.匿名內部類別
匿名內部類別應該是平時我們編寫程式碼時用得最多的,在編寫事件監聽的程式碼時使用匿名內部類別不但方便,而且使程式碼更加容易維護。下面這段程式碼是一段Android事件監聽程式碼:
scan_bt.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub } }); history_bt.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub } });
这段代码为两个按钮设置监听器,这里面就使用了匿名内部类。具体位置是这段:
new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub } }
代码中需要给按钮设置监听器对象,使用匿名内部类能够在实现父类或者接口中的方法情况下同时产生一个相应的对象,但是前提是这个父类或者接口必须先存在才能这样使用。当然像下面这种写法也是可以的,跟上面使用匿名内部类达到效果相同:
private void setListener() { scan_bt.setOnClickListener(new Listener1()); history_bt.setOnClickListener(new Listener2()); } class Listener1 implements View.OnClickListener{ @Override public void onClick(View v) { // TODO Auto-generated method stub } } class Listener2 implements View.OnClickListener{ @Override public void onClick(View v) { // TODO Auto-generated method stub } }
这种写法虽然能达到一样的效果,但是既冗长又难以维护,所以一般使用匿名内部类的方法来编写事件监听代码。同样的,匿名内部类也是不能有访问修饰符和static修饰符的。
匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为Outter$1.class。一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。