一、什么是嵌套類及內(nèi)部類? 可以在一個(gè)類的內(nèi)部定義另一個(gè)類,這種類稱為嵌套類(nested classes),它有兩種類型: 靜態(tài)嵌套類和非靜態(tài)嵌套類。靜態(tài)嵌套類使用很少,最重要的是非靜態(tài)嵌套類,也即是被稱作為內(nèi)部類(inner)。嵌套類從JDK1.1開始引入。其中inner類又可分為三種: 其一、在一個(gè)類(外部類)中直接定義的內(nèi)部類; 其二、在一個(gè)方法(外部類的方法)中定義的內(nèi)部類; 其三、匿名內(nèi)部類。 下面,我將說明這幾種嵌套類的使用及注意事項(xiàng)。 | |
|
二、靜態(tài)嵌套類
如下所示代碼為定義一個(gè)靜態(tài)嵌套類,
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";//內(nèi)部類公有成員
public void display(){
//System.out.println(id);//不能直接訪問外部類的非靜態(tài)成員
System.out.println(name);//只能直接訪問外部類的靜態(tài)成員
System.out.println("Inner "+address);//訪問本內(nèi)部類成員。
}
}
public void printInfo(){
Person person = new Person();
person.display();
//System.out.println(mail);//不可訪問
//System.out.println(address);//不可訪問
System.out.println(person.address);//可以訪問內(nèi)部類的私有成員
System.out.println(person.mail);//可以訪問內(nèi)部類的公有成員
}
public static void main(String[] args) {
StaticTest staticTest = new StaticTest();
staticTest.printInfo();
}
}
若想訪問外部類的變量,必須通過其它方法解決,由于這個(gè)原因,靜態(tài)嵌套類使用很少。注意,外部類訪問內(nèi)
部類的的成員有些特別,不能直接訪問,但可以通過內(nèi)部類實(shí)例來訪問,這是因?yàn)殪o態(tài)嵌套內(nèi)的所有成員和方法默認(rèn)為
靜態(tài)的了。同時(shí)注意,內(nèi)部靜態(tài)類Person只在類StaticTest 范圍內(nèi)可見,若在其它類中引用或初始化,均是錯(cuò)誤的。
三、在外部類中定義內(nèi)部類
如下所示代碼為在外部類中定義兩個(gè)內(nèi)部類及它們的調(diào)用關(guān)系:
class Outer{ int outer_x = 100; private class Inner{//私有的內(nèi)部類 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); } } public Inner getInner(){//即使是對(duì)外公開的方法,外部類也無法調(diào)用 return new Inner(); } void test(){ Inner inner = new Inner(); //可以訪問 inner.display(); inner.display2(); //System.out.println("Inner y:" + y);//不能訪問內(nèi)部?jī)?nèi)變量 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 = getInner();//可以訪問 public void show(){ //System.out.println(y);//不可訪問Innter的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 class Test { public static void main(String args[]){ Outer outer = new Outer(); // Outer.Inner a=outer.getInner();//Inner類是私有的,外部類不能訪問,如果Inner類是public ,則可以。 outer.test(); } }
中的方法,不可直接訪問內(nèi)部類的變量。
四、在方法中定義內(nèi)部類
如下所示代碼為在方法內(nèi)部定義一個(gè)內(nèi)部類:
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);//不可訪問本方法內(nèi)部的非final變量
//System.out.println(str2);//不可訪問本方法內(nèi)部的非final變量
System.out.println(str3);//只可訪問本方法的final型變量成員
}
}
InnerTwo innerTwo = new InnerTwo();
innerTwo.testPrint();
}
public void use(){
//Inner innerObj = new Inner();//此時(shí)Inner己不可見了。
//System.out.println(Inner.x);//此時(shí)Inner己不可見了。
}
public static void main(String[] args) {
FunOuter outer = new FunOuter();
outer.test();
}
}
從上面的例程我們可以看出定義在方法內(nèi)部的內(nèi)部類的可見性更小,它只在方法內(nèi)部 可見,在外部類(及外部類的其它方法中)中都不可見了。同時(shí),它有一個(gè)特點(diǎn),就是方法內(nèi)的內(nèi)部類連本方法的成員變量都不可訪問,它只能訪問本方法的final型成員。同時(shí)另一個(gè)需引起注意的是方法內(nèi)部定義成員,只允許final修飾或不加修飾符,其它像static等均不可用。
五、匿名內(nèi)部類
如下所示代碼為定義一個(gè)匿名內(nèi)部類:匿名內(nèi)部類通常用在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接受一個(gè)對(duì)象型的參數(shù)表達(dá)式,于是,在參數(shù)里,我們定義了一個(gè)匿名內(nèi)部類,這個(gè)類是一個(gè)MouseAdapter類型的類,同時(shí)在這個(gè)類中定義了一個(gè)繼承的方法mousePressed,整個(gè)類做為一個(gè)參數(shù)。這個(gè)類沒有名稱,但是當(dāng)執(zhí)行這個(gè)表達(dá)式時(shí)它被自動(dòng)實(shí)例化。同時(shí)因?yàn)椋@個(gè)匿名內(nèi)部類是定義在AnonymousInnerClassDemo 類內(nèi)部的,所以它可以訪問它的方法showStatus。這同前面的內(nèi)部類是一致的。
六、內(nèi)部類使用的其它的問題
通過以上,我們可以清楚地看出內(nèi)部類的一些使用方法,同時(shí),在許多時(shí)候,內(nèi)部類是在如Java的事件處理、或做為值對(duì)象來使用的。同時(shí),我們需注意最后一個(gè)問題,那就是,內(nèi)部類同其它類一樣被定義,同樣它也可以繼承外部其它包的類和實(shí)現(xiàn)外部其它地方的接口。同樣它也可以繼承同一層次的其它的內(nèi)部類,甚至可以繼承外部類本身。下面我們給出最后一個(gè)例子做為結(jié)束:
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();
}
//內(nèi)部類的內(nèi)部類,多層內(nèi)部類
class Email{
String mailID;
String mailNetAddress;
Email(String mailId,String mailNetAddress){
this.mailID = mailId;
this.mailNetAddress = mailNetAddress;
}
String getMailStr(){
return this.mailID +"@"+this.mailNetAddress;
}
}
}
//另一個(gè)內(nèi)部類繼承外部類本身
class ChildLayer extends Layer{
void print(){
System.out.println(super.testStr);//訪問父類的成員變量
}
}
//另個(gè)內(nèi)部類繼承內(nèi)部類Person
class OfficePerson extends Person{
void show(){
System.out.println(name);
System.out.println(getEmail());
}
}
//外部類的測(cè)試方法
public void testFunction(){
//測(cè)試第一個(gè)內(nèi)部類
ChildLayer childLayer = new ChildLayer();
childLayer.print();
//測(cè)試第二個(gè)內(nèi)部類
OfficePerson officePerson = new OfficePerson();
officePerson.setName("abner chai");
//注意此處,必須用對(duì)象.new 出來對(duì)象的子類對(duì)象
//而不是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();
}
}