首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

深入理解 Java 巢狀類與內部類

     編輯:Java 相關知識

一、什麼是巢狀類與內部類?

可以在一個類內部定義另一個類,這類稱為巢狀類,它有兩種類型:靜態巢狀類與非靜態巢狀類。靜態巢狀類使用較少,最重要的是非靜態巢狀類,即所謂內部類。巢狀類從 JDK 1.1 引入。內部類又可分三種:

  1. 在一個類(外部類)中直接定義的內部類;
  2. 在一個方法(外部類方法)中定義的內部類;
  3. 匿名內部類。

下面說明這幾種巢狀類使用與注意事項。

二、靜態巢狀類

如下代碼定義一個靜態巢狀類:

public class StaticTest {
private static String name = "javaJohn";
private String id = "X001";
static class Person{
private String address = "swjtu,chenDu,China";
public String mail = "josserchai@yahoo.com";// 內部類公有成員
public void display(){
// System.out.println(id); // 不能直接訪問外部類非靜態成員
System.out.println(name); // 只能直接訪問外部類靜態成員
System.out.println("Inner " + address); // 訪問本內部類成員。
}
}
public void printInfo(){
Person person = new Person();
person.display();
// System.out.println(mail); // 不可訪問
// System.out.println(address); // 不可訪問
System.out.println(person.address); // 可以訪問內部類私有成員
System.out.println(person.mail); // 可以訪問內部類公有成員
}
public static void main(String[] args) {
StaticTest staticTest = new StaticTest();
staticTest.printInfo();
}
}

在靜態巢狀類內部,不能訪問外部類非靜態成員,這由 Java 語法「靜態方法不能直接訪問非靜態成員」限定。若想訪問外部類變數,必須透過其他方法解決,因這原因靜態巢狀類使用較少。注意:外部類訪問內部類成員有些特別,不能直接訪問,但可透過內部類實例訪問,因靜態巢狀內所有成員與方法預設為靜態。同時注意,內部靜態類 Person 僅在 StaticTest 範圍內可見,若在其他類中引用或初始化均錯誤。

三、在外部類中定義內部類

如下代碼在外部類中定義兩個內部類及它們調用關係:

public class Outer{
int outer_x = 100;
class Inner{
public int y = 10;
private int z = 9;
int m = 5;
public void display(){
System.out.println("display outer_x:" + outer_x);
}
private void display2(){
System.out.println("display outer_x:" + outer_x);
}
}
void test(){
Inner inner = new Inner();
inner.display();
inner.display2();
// System.out.println("Inner y:" + y); // 不能訪問內部內變量
System.out.println("Inner y:" + inner.y); // 可以訪問
System.out.println("Inner z:" + inner.z); // 可以訪問
System.out.println("Inner m:" + inner.m); // 可以訪問
InnerTwo innerTwo = new InnerTwo();
innerTwo.show();
}
class InnerTwo{
Inner innerx = new Inner();
public void show(){
// System.out.println(y); // 不可訪問 Inner 的 y 成員
// System.out.println(Inner.y); // 不可直接訪問 Inner 任何成員和方法
innerx.display(); // 可以訪問
innerx.display2(); // 可以訪問
System.out.println(innerx.y); // 可以訪問
System.out.println(innerx.z); // 可以訪問
System.out.println(innerx.m); // 可以訪問
}
}
public static void main(String args[]){
Outer outer = new Outer();
outer.test();
}
}

以上代碼需說明:對內部類,通常在定義類 class 關鍵字前不加 public 或 private 等限制符,若加了無影響,同時好像這些限定符對內部類變量與方法也無影響。另外注意,內部類 Inner 及 InnerTwo 僅在 Outer 作用域內可知,若 Outer 外任何代碼嘗試初始化 Inner 或使用它,編譯不通過。同時內部類變量成員只在內部內部可見,若外部類或同層次內部類需訪問,需採用示例程式方法,不可直接訪問內部類變量。

四、在方法中定義內部類

如下代碼在方法內部定義一個內部類:

public class FunOuter {
int out_x = 100;
public void test(){
class Inner{
String x = "x";
void display(){
System.out.println(out_x);
}
}
Inner inner = new Inner();
inner.display();
}
public void showStr(String str){
// public String str1 = "test Inner"; // 不可定義,只允許 final 修飾
// static String str4 = "static Str"; // 不可定義,只允許 final 修飾
String str2 = "test Inner";
final String str3 = "final Str";
class InnerTwo{
public void testPrint(){
System.out.println(out_x); // 可直接訪問外部類變量
// System.out.println(str); // 不可訪問本方法內部非 final 變量
// System.out.println(str2); // 不可訪問本方法內部非 final 變量
System.out.println(str3); // 只可訪問本方法 final 型變量成員
}
}
InnerTwo innerTwo = new InnerTwo();
innerTwo.testPrint();
}
public void use(){
// Inner innerObj = new Inner(); // 此時 Inner 已不可見
// System.out.println(Inner.x); // 此時 Inner 已不可見
}
public static void main(String[] args) {
FunOuter outer = new FunOuter();
outer.test();
}
}

從例程可見定義在方法內部的內部類可見性更小,僅在方法內部可見,外部類(及其他方法)中不可見。同時它一特點:方法內內部類連本方法成員變量都不可訪問,只能訪問本方法 final 型成員。另一需注意:方法內部定義成員只允許 final 修飾或不加修飾符,其他如 static 均不可用。

五、匿名內部類

如下代碼定義一個匿名內部類:匿名內部類通常用在 Java 事件處理上。

import java.applet.*;
import java.awt.event.*;
public class AnonymousInnerClassDemo extends Applet{
public void init(){
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent me){
showStatus("Mouse Pressed!");
}
})
}
public void showStatus(String str){
System.out.println(str);
}
}

在上面例子中,方法 addMouseListener 接受一個物件型參數表達式,於是在參數裡定義一個匿名內部類,此類是 MouseAdapter 型別,同時在類中定義一個繼承方法 mousePressed,整個類作為一個參數。這類沒有名稱,但執行此表達式時自動實例化。同時因這匿名內部類定義在 AnonymousInnerClassDemo 類內部,所以可訪問其方法 showStatus。這與前面內部類一致。

六、內部類使用的其他問題

通過以上可清楚看出內部類一些使用方法,同時許多時候內部類用於 Java 事件處理、或作為值物件使用。同時需注意最後一個問題:內部類同其他類一樣被定義,同樣可繼承外部其他包類與實現外部其他地方介面。同樣可繼承同層次其他內部類,甚至繼承外部類本身。下面給出最後一個例子作結束:

public class Layer {
// Layer 類成員變量
private String testStr = "testStr";
// Person 類,基類
class Person{
String name;
Email email;
public void setName(String nameStr){ this.name = nameStr; }
public String getName(){ return this.name; }
public void setEmail(Email emailObj){ this.email = emailObj; }
public String getEmail(){ return this.email.getMailStr(); }
// 內部類的內部類,多層內部類
class Email{
String mailID;
String mailNetAddress;
Email(String mailId,String mailNetAddress){
this.mailID = mailId;
this.mailNetAddress = mailNetAddress;
}
String getMailStr(){ return this.mailID + "@" + this.mailNetAddress; }
}
}
// 另一個內部類繼承外部類本身
class ChildLayer extends Layer{
void print(){ System.out.println(super.testStr); // 訪問父類成員變量
}
}
// 另個內部類繼承內部類 Person
class OfficePerson extends Person{
void show(){
System.out.println(name);
System.out.println(getEmail());
}
}
// 外部類測試方法
public void testFunction(){
// 測試第一個內部類
ChildLayer childLayer = new ChildLayer();
childLayer.print();
// 測試第二個內部類
OfficePerson officePerson = new OfficePerson();
officePerson.setName("abner chai");
// 注意此處,必須用 外部物件.new 出來物件的子類物件
// 而不是 Person.new Email(...)
// 也不是 new Person.Email(...)
officePerson.setEmail(officePerson.new Email("josserchai","yahoo.com"));
officePerson.show();
}
public static void main(String[] args) {
Layer layer = new Layer();
layer.testFunction();
}
}

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved