Java編程思想——細話Java內部類(上)

  • 置於其他類內部的類就是內部類
  • 內部類瞭解外部類並能與外部類進行通信
  • 內部類和組合並不是一個概念

一、內部類的創建

內部類小例子:

class A{
  class B{  //內部類的方法體與普通類相同
     private int num=0;
     B(){}
     void f(){}
  }
  private String name="Hello";
  public void setName(String name){
    this.name=name;
  }
}

外部類調用內部類:

class A{
   class B{  //內部類(內部構造和普通類一樣)
      private String name;
      B(String name){
	this.name=name;
      }
     public String getName(){
        return name;
     }
   }
   public B getB(String name){
     return new B(name);
   }
}
public class C{
  public static void main(String[] args)
  { 
     A a=new A();
     A.B b=a.getB("Hello Java!");
     System.out.print(b.getName());
  }
}

將上述例子反編譯可以看到經過編譯器編譯後的代碼樣式:


可以看出內部類同樣會被編譯到一個單獨的.class文件中,但在其所在的類的編譯文件中同樣含有內部類。

二、與外部類的通信

當生成一個內部類的對象時,此對象與構造它的外圍對象之間就有一中聯繫,所以它能訪問外圍對象的所有成員(包括private私有成員),而不需要任何特殊條件。(C++中的內部類只是單純的名字隱藏機制而不能和外圍對象進行聯繫,也沒有隱含的訪問權)。

一個小例子:

public class Test{
   private static Object[] obj;
   private static int i=0;
   private void add(int i){
	  obj[this.i]=i;
	  this.i++;
   }
   class RunTest{
     public void insertValues(){
	obj=new Object[10];//使用外圍類的私有成員
	for(int ind=0;ind<10;ind++){
	    add(ind);//使用外圍類的私有方法
	} 
      }
   } 
   public RunTest getRunTest(){
	   return new RunTest();
   }
    public static void main(String[] args){
	   Test test=new Test();
	   Test.RunTest t=test.getRunTest();
	   t.insertValues();
       for(int i=0;i<obj.length;i++){
          System.out.print(obj[i]+" ");
       }
    }
}

反編譯後的內部類如下:

class Test$RunTest
{
  Test$RunTest(Test paramTest) {}
  public void insertValues()
  {
    Test.access$002(new Object[10]);
    for (int i = 0; i < 10; i++) {
      Test.access$100(this.this$0, i);
    }
  }
}
可以看到當內部類訪問外圍類中成員以及私有方法時會自動獲取外圍類的引用並通過引用訪問成員和方法。

**如何用其他方式獲取內部類和外圍類的引用對象?**

  • 內部類獲取外圍類對象——通過".this"
  • 外圍類獲取內部類對象——通過“.new”
public class A{
   class B{
      public A getA(){
         //獲取A的引用
         return A.this;
      }
   }
    public B getB(){
       //通過方法獲取B的對象
       return new B();
    }
   public static void main(String[] args){
      //通過構造器獲取A的對象引用
      A a=new A();
      //通關方法調用獲取內部類對象
      A.B b=a.getB(); 
      //通過“.new”獲取內部類對象
      A.B b2=a.new B();
      //通過調用內部類方法獲取A的引用
      A a2=b2.getA();
   }
}

*我們來看看這些創建方法的經過編譯後是什麼樣的:

//".this"——this.this$0 
public A getA()
{
  return this.this$0;
}     
//".new"——
{
  tmp18_17 = localA1;
  tmp18_17.getClass();
  A.B localB2 = new A.B(tmp18_17);
  localB2.g();
}
”this$0“——特指該內部類所在的外部類的引用

通過這些可知:

      要想直接創建內部類的對象,不能脫離外部類,而必須使用外部類的對象創建內部類對象,這是因爲內部類對象會暗暗地連接到創建它的外部類對象上。但是有一種特殊情況就是靜態內部類,它是不需要對外部類對象的引用的,直接通過new創建對象。

三、各個域中的內部類

     以上內部類都是定義在外部類中與方法和成員變量地位相同,其實內部類可以放在外部類的任意作用域中,具體可見如下例子:

public class A{
  //在與方法平行的位置定義內部類
  class class B{}
  public void show(){
     //在方法內部定義內部類
     class C{
        System.out.print("Hello");
     }
  }
  public void isShow(){
     if(true){
        //在判斷語句的域中創建內部類
        class D{}
     }
  }
}

注意:

      無論我們將內部類定義在哪個域中,其都是與所有類同時被編譯器編譯的,所以條件if下的類D也並不是在滿足條件的情況下才創建的。唯一有區別的是這些內部類只在自己所在的域內有效,其他位置均不可用。

public class A{
   public void show(){
      if(true){
          class B{
              public void isShow(){
                 System.out.print("is if class");
              }
          }
        B b=new B();
        b.isShow();
      }
        //在if域外使用B報錯找不到符號B
        //B b=new B();
        //b.isShow();
   }
}

另外,對於內部類的向上轉型和其他普通類是一樣的。

未完待續。。。。。。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章