1. 程式人生 > >JAVA內部類(成員內部類、區域性內部類、匿名內部類、靜態內部類)

JAVA內部類(成員內部類、區域性內部類、匿名內部類、靜態內部類)

    在Java中,可以將一個類定義在另一個類裡面或者一個方法裡面,這樣的類稱為內部類。廣泛意義上的內部類一般來說包括這四種:成員內部類、區域性內部類、匿名內部類和靜態內部類。下面就先來了解一下這四種內部類的用法。

  1.成員內部類

  成員內部類是最普通的內部類,它的定義為位於另一個類的內部,形如下面的形式:

1

2

3

4

5

6

7

8

9

10

11

12

13

class Circle {

double radius = 0;

public

 Circle(double radius) {

this.radius = radius;

}

class Draw {     //內部類

public void drawSahpe() {

System.out.println("drawshape");

}

}

}

  這樣看起來,類Draw像是類Circle的一個成員,Circle稱為外部類。成員內部類可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態成員)。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

class Circle {

private double radius = 0;

public static int count =1;

public Circle(double radius) {

this.radius = radius;

}

class Draw {     //內部類

public void drawSahpe() {

System.out.println(radius);  

//外部類的private成員

System.out.println(count);   //外部類的靜態成員

}

}

}

  不過要注意的是,當成員內部類擁有和外部類同名的成員變數或者方法時,會發生隱藏現象,即預設情況下訪問的是成員內部類的成員。如果要訪問外部類的同名成員,需要以下面的形式進行訪問:

1

2

外部類.this.成員變數

外部類.this.成員方法

  雖然成員內部類可以無條件地訪問外部類的成員,而外部類想訪問成員內部類的成員卻不是這麼隨心所欲了。在外部類中如果要訪問成員內部類的成員,必須先建立一個成員內部類的物件,再通過指向這個物件的引用來訪問:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

class Circle {

private double radius = 0;

public Circle(double radius) {

this.radius = radius;

getDrawInstance().drawSahpe();   //必須先建立成員內部類的物件,再進行訪問

}

private Draw getDrawInstance() {

return new Draw();

}

class Draw {     //內部類

public void drawSahpe() {

System.out.println(radius);  //外部類的private成員

}

}

}

  成員內部類是依附外部類而存在的,也就是說,如果要建立成員內部類的物件,前提是必須存在一個外部類的物件。建立成員內部類物件的一般方式如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

public class Test {

public static void main(String[] args)  {

//第一種方式:

Outter outter = new Outter();

Outter.Inner inner = outter.new Inner();  //必須通過Outter物件來建立

//第二種方式:

Outter.Inner inner1 = outter.getInnerInstance();

}

}

class Outter {

private Inner inner = null;

public Outter() {

}

public Inner getInnerInstance() {

if(inner == null)

inner = new Inner();

return inner;

}

class Inner {

public Inner() {

}

}

}

  內部類可以擁有private訪問許可權、protected訪問許可權、public訪問許可權及包訪問許可權。比如上面的例子,如果成員內部類Inner用private修飾,則只能在外部類的內部訪問,如果用public修飾,則任何地方都能訪問;如果用protected修飾,則只能在同一個包下或者繼承外部類的情況下訪問;如果是預設訪問許可權,則只能在同一個包下訪問。這一點和外部類有一點不一樣,外部類只能被public和包訪問兩種許可權修飾。我個人是這麼理解的,由於成員內部類看起來像是外部類的一個成員,所以可以像類的成員一樣擁有多種許可權修飾。

  2.區域性內部類

  區域性內部類是定義在一個方法或者一個作用域裡面的類,它和成員內部類的區別在於區域性內部類的訪問僅限於方法內或者該作用域內。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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.匿名內部類

  匿名內部類應該是平時我們編寫程式碼時用得最多的,在編寫事件監聽的程式碼時使用匿名內部類不但方便,而且使程式碼更加容易維護。下面這段程式碼是一段Android事件監聽程式碼:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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

}

});

  這段程式碼為兩個按鈕設定監聽器,這裡面就使用了匿名內部類。這段程式碼中的:

1

2

3

4

5

6

7

8

new OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

}

}

  就是匿名內部類的使用。程式碼中需要給按鈕設定監聽器物件,使用匿名內部類能夠在實現父類或者介面中的方法情況下同時產生一個相應的物件,但是前提是這個父類或者介面必須先存在才能這樣使用。當然像下面這種寫法也是可以的,跟上面使用匿名內部類達到效果相同。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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。一般來說,匿名內部類用於繼承其他類或是實現介面,並不需要增加額外的方法,只是對繼承方法的實現或是重寫。

  4.靜態內部類

  靜態內部類也是定義在另一個類裡面的類,只不過在類的前面多了一個關鍵字static。靜態內部類是不需要依賴於外部類的,這點和類的靜態成員屬性有點類似,並且它不能使用外部類的非static成員變數或者方法,這點很好理解,因為在沒有外部類的物件的情況下,可以建立靜態內部類的物件,如果允許訪問外部類的非static成員就會產生矛盾,因為外部類的非static成員必須依附於具體的物件。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

public class Test {

public static void main(String[] args)  {

Outter.Inner inner = new Outter.Inner();

}

}

class Outter {

public Outter() {

}

static class Inner {

public Inner() {

}

}

}