深入的理解嵌套類和內部類

Java   內置了多線程,  
   
  想象一下:  
  我現在在一個方法裏面定義了一個   內部類   它需要用到這個方法的局部變量,但是這個內部類是在另一個線程中啓動調用的,那個線程和這個方法調用的線程不是同一個調用堆棧,當那個線程調用了這個內部類的方法,這個時候定義這個內部類的方法的那個局部變量的值是不是變得不可預測了?   這兩個線程是獨立執行的,爲了消除這個很容易出現的錯誤,Java   語言要求這樣以使代碼簡單、安全. 

  

一、什麼是嵌套類及內部類?
  可以在一個類的內部定義另一個類,這種類稱爲嵌套類(nested classes),它有兩種類型:
  靜態嵌套類和非靜態嵌套類。靜態嵌套類使用很少,最重要的是非靜態嵌套類,也即是被稱作爲
  內部類(inner)。嵌套類從JDK1.1開始引入。其中inner類又可分爲三種:
  其一、在一個類(外部類)中直接定義的內部類;
  其二、在一個方法(外部類的方法)中定義的內部類;
  其三、匿名內部類。
  下面,我將說明這幾種嵌套類的使用及注意事項。
  二、靜態嵌套類
  如下所示代碼爲定義一個靜態嵌套類,
  publicclass StaticTest {
  privatestatic String name = "javaJohn";
  private String id = "X001";
  staticclass Person{
  private String address = "swjtu,chenDu,China";
  public String mail = "[email protected]";//內部類公有成員
 
  publicvoid display(){
  //System.out.println(id);//不能直接訪問外部類的非靜態成員
 
  System.out.println(name);//只能直接訪問外部類的靜態成員
 
  System.out.println("Inner "+address);//訪問本內部類成員。
 
  }
  }
  publicvoid 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);//可以訪問內部類的公有成員
 
  }
  publicstaticvoid main(String[] args) {
  StaticTest staticTest = new StaticTest();
  staticTest.printInfo();
  }
  }
 
  在靜態嵌套類內部,不能訪問外部類的非靜態成員,這是由Java語法中"靜態方法不能直接訪問非靜態成員"所限定。
  若想訪問外部類的變量,必須通過其它方法解決,由於這個原因,靜態嵌套類使用很少。注意,外部類訪問內部類的的成員有些特別,不能直接訪問,但可以通過內部類來訪問,這是因爲靜態嵌套內的所有成員和方法默認爲靜態的了。同時注意,內部靜態類Person只在類StaticTest 範圍內可見,若在其它類中引用或初始化,均是錯誤的。
  三、在外部類中定義內部類
  如下所示代碼爲在外部類中定義兩個內部類及它們的調用關係:
  publicclass Outer{
  int outer_x = 100;
  class Inner{
  publicint y = 10;
  privateint z = 9;
  int m = 5;
  publicvoid display(){
  System.out.println("display outer_x:"+ outer_x);
  }
  privatevoid 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();
  publicvoid 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);//可以訪問
 
  }
  }
  publicstaticvoid main(String args[]){
  Outer outer = new Outer();
  outer.test();
  }
  }
 
  以上代碼需要說明有,對於內部類,通常在定義類的class關鍵字前不加public 或 private等限制符,若加了沒有任何影響,同時好像這些限定符對內部類的變量和方法也沒有影響(?)。另外,就是要注意,內部類Inner及InnterTwo只在類Outer的作用域內是可知的,如果類Outer外的任何代碼嘗試初始化類Inner或使用它,編譯就不會通過。同時,內部類的變量成員只在內部內內部可見,若外部類或同層次的內部類需要訪問,需採用示例程序中的方法,不可直接訪問內部類的變量。
  四、在方法中定義內部類
  如下所示代碼爲在方法內部定義一個內部類:
  publicclass FunOuter {
  int out_x = 100;
  publicvoid test(){
  class Inner{
  String x = "x";
  void display(){
  System.out.println(out_x);
  }
  }
  Inner inner = new Inner();
  inner.display();
  }
  publicvoid 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{
  publicvoid 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();
  }
  publicvoid use(){
  //Inner innerObj = new Inner();//此時Inner己不可見了。
  //System.out.println(Inner.x);//此時Inner己不可見了。
 
  }
  publicstaticvoid main(String[] args) {
  FunOuter outer = new FunOuter();
  outer.test();
  }
  }
 
  從上面的例程我們可以看出定義在方法內部的內部類的可見性更小,它只在方法內部
  可見,在外部類(及外部類的其它方法中)中都不可見了。同時,它有一個特點,就是方法
  內的內部類連本方法的成員變量都不可訪問,它只能訪問本方法的final型成員。同時另一個
  需引起注意的是方法內部定義成員,只允許final修飾或不加修飾符,其它像static等均不可用。
  五、匿名內部類
  如下所示代碼爲定義一個匿名內部類:匿名內部類通常用在Java的事件處理上
  import java.applet.*;
  import java.awt.event.*;
  publicclass AnonymousInnerClassDemo extends Applet{
  publicvoid init(){
  addMouseListener(new MouseAdapter(){
  publicvoid mousePressed(MouseEvent me){
  showStatus("Mouse Pressed!");
  }
  })
  }
  publicvoid showStatus(String str){
  System.out.println(str);
  }
  }
 
  在上面的例子中,方法addMouseListener接受一個對象型的參數表達式,於是,在參數裏,我們定義了一個匿名內部類這個類是一個MouseAdapter類型的類,同時在這個類中定義了一個繼承的方法mousePressed,整個類做爲一個參數。這個類沒有名稱,但是當執行這個表達式時它被自動實例化。同時因爲,這個匿名內部類是定義在AnonymousInnerClassDemo 類內部的,所以它可以訪問它的方法showStatus。這同前面的內部類是一致的。
  六、內部類使用的其它的問題
  通過以上,我們可以清楚地看出內部類的一些使用方法,同時,在許多時候,內部類是在如Java的事件處理、或做爲值對象來使用的。同時,我們需注意最後一個問題,那就是,內部類同其它類一樣被定義,同樣它也可以繼承外部其它包的類和實現外部其它地方的接口。同樣它也可以繼承同一層次的其它的內部類,甚至可以繼承外部類本身。下面我們給出最後一個例子做爲結束:
  publicclass Layer {
  //Layer類的成員變量
 
  private String testStr = "testStr";
  //Person類,基類
 
  class Person{
  String name;
  Email email;
  publicvoid setName(String nameStr){
  this.name = nameStr;
  }
  public String getName(){
  returnthis.name;
  }
  publicvoid setEmail(Email emailObj){
  this.email = emailObj;
  }
  public String getEmail(){
  returnthis.email.getMailStr();
  }
  //內部類的內部類,多層內部類
 
  class Email{
  String mailID;
  String mailNetAddress;
  Email(String mailId,String mailNetAddress){
  this.mailID = mailId;
  this.mailNetAddress = mailNetAddress;
  }
  String getMailStr(){
  returnthis.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());
  }
  }
  //外部類的測試方法
 
  publicvoid 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();
  }
  publicstaticvoid main(String[] args) {
  Layer layer = new Layer();
  layer.testFunction();
  }
  }
 
1
 
發佈了6 篇原創文章 · 獲贊 0 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章