詳細解釋Java內部類
為什麼要使用內部類?在《Think in java》中有這樣一句話:使用內部類最吸引人的原因是:每個內部類都能獨立地繼承一個(介面的)實現,所以無論外圍類是否已經繼承了某個(介面的)實現,對於內部類都沒有影響。
在我們程式設計中有時候會存在一些使用介面很難解決的問題,這個時候我們可以利用內部類提供的、可以繼承多個具體的或者抽象的類的能力來解決這些程式設計問題。可以這樣說,介面只是解決了部分問題,而內部類使得多重繼承的解決方案變得更加完整。
內部類基礎
package com.ligz.Inner; public class OuterClass { private String name; private String age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } //InnerClass public class InnerClass { public InnerClass() { name="ligz"; age="18"; } public void display() { System.out.println("name:"+name+" age:"+age); } } public static void main(String[] args) { OuterClass outerClass = new OuterClass(); OuterClass.InnerClass innerClass = outerClass.new InnerClass(); innerClass.display(); } }
引用內部類我們需要指明這個物件的型別:OuterClasName.InnerClassName。同時如果我們需要建立某個內部類物件,必須要利用外部類的物件通過.new來建立內部類: OuterClass.InnerClass innerClass = outerClass.new InnerClass();
我們也可以通過下面的方法得到:
public InnerClass getInner() {
return this.new InnerClass();
}
建立的方法是
OuterClass.InnerClass innerClass = outerClass.getInner();
同時如果我們需要生成對外部類物件的引用,可以使用OuterClassName.this,這樣就能夠產生一個正確引用外部類的引用了
public class InnerClass{
public OuterClass getOuterClass(){
return OuterClass.this;
}
}
不過要注意的是,當成員內部類擁有和外部類同名的成員變數或者方法時,會發生隱藏現象,即預設情況下訪問的是成員內部類的成員。如果要訪問外部類的同名成員,需要以下面的形式進行訪問:
外部類.this.成員變數 外部類.this.成員方法
內部類可以擁有private訪問許可權、protected訪問許可權、public訪問許可權及包訪問許可權。比如上面的例子,如果成員內部類Inner用private修飾,則只能在外部類的內部訪問,如果用public修飾,則任何地方都能訪問;如果用protected修飾,則只能在同一個包下或者繼承外部類的情況下訪問;如果是預設訪問許可權,則只能在同一個包下訪問。這一點和外部類有一點不一樣,外部類只能被public和包訪問兩種許可權修飾。我個人是這麼理解的,由於成員內部類看起來像是外部類的一個成員,所以可以像類的成員一樣擁有多種許可權修飾。
2、區域性內部類
class People{
public People() {
}
}
class Man{
public Man(){
}
public People getWoman(){
class Woman extends People{ //區域性內部類
int age =0;
}
return new Woman();
}
}
區域性內部類我不太熟悉,但區域性內部類就像是方法裡面的一個區域性變數一樣,是不能有public、protected、private以及static修飾符的。
3、最重要的匿名內部類
不用匿名內部類的時候:
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
}
}
使用匿名內部類:
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
}
});
匿名內部類是唯一一種沒有構造器的類。正因為其沒有構造器,所以匿名內部類的使用範圍非常有限,大部分匿名內部類用於介面回撥。匿名內部類在編譯的時候由系統自動起名為Outter$1.class。一般來說,匿名內部類用於繼承其他類或是實現介面,並不需要增加額外的方法,只是對繼承方法的實現或是重寫。
我們在通過一個例子詳細的說明匿名內部類:
public abstract class Dog {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract int run();
}
public class Inner {
public void Inner(Dog dog) {
System.out.println(dog.getName()+"能奔跑"+dog.run()+"米");
}
public static void main(String[] args) {
Inner inner = new Inner();
inner.Inner(new Dog() {
@Override
public int run() {
return 10000;
}
public String getName() {
return "阿拉伯獵犬";
}
});
}
}
在這一段程式碼裡面我們通過呼叫匿名內部類Dog。得到——阿拉伯獵犬能奔跑10000米。
1、使用匿名內部類時,我們必須是繼承一個類或者實現一個介面,但是兩者不可兼得,同時也只能繼承一個類或者實現一個介面。
2、匿名內部類中是不能定義建構函式的。
3、匿名內部類中不能存在任何的靜態成員變數和靜態方法。
4、匿名內部類為區域性內部類,所以區域性內部類的所有限制同樣對匿名內部類生效。
5、匿名內部類不能是抽象的,它必須要實現繼承的類或者實現的介面的所有抽象方法。
我們給匿名內部類傳遞引數的時候,若該形參在內部類中需要被使用,那麼該形參必須要為final。也就是說:當所在的方法的形參需要被內部類裡面使用時,該形參必須為final。
簡單理解就是,拷貝引用,為了避免引用值發生改變,例如被外部類的方法修改等,而導致內部類得到的值不一致,於是用final來讓該引用不可改變。
故如果定義了一個匿名內部類,並且希望它使用一個其外部定義的引數,那麼編譯器會要求該引數引用是final的。
4.靜態內部類
瞭解static關鍵字的應該很好理解靜態內部類
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}
我們參考的部落格有:
http://www.cnblogs.com/chenssy/p/3388487.html