1. 程式人生 > >詳細解釋Java內部類

詳細解釋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

https://www.cnblogs.com/dolphin0520/p/3811445.html

http://www.cnblogs.com/chenssy/p/3390871.html