你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> Thinking in Java之內部類

Thinking in Java之內部類

編輯:關於IOS

        前言

          學習Java已經有一段日子了,最近的日子筆者在重新對java進行再學習。不過這個階段的學習

    筆者不會再著眼於具體的語法哪些細枝末節的東西了,這個階段的學習中筆者將會對以前學習的

    模糊的,遺漏的知識概念做一些相關性的總結。今天,恰好看到內部類這塊了,記得以前對內部類

    的使用就有一些模糊,因此專門就內部類做一些總結。

      內部類概念
               所謂內部類就是指在一個外部類中再定義一個類(內部類),這樣內部類就作為一個成員依附於

          外部類而存在。不過在使用內部類的時候需要注意的是內部類可以static,protect,private,但是

          外部類只能使用public和缺省的包訪問權限.

            若非這兩種編譯出錯:

            Illegal modifier for the class Outer; only public, abstract & final are permitted 

[java]
package com.kiritor; 
public class Outer { 
    private String type; 
 
    public String getType() { 
        return type; 
    } 
 
    public void setType(String type) { 
        this.type = type; 
    } 
 
    class Inner { 
        private String type; 
 
        public String getType() { 
            return type; 
        } 
 
        public void setType(String type) { 
            this.type = type; 
        } 
 
    } 

package com.kiritor;
public class Outer {
 private String type;

 public String getType() {
  return type;
 }

 public void setType(String type) {
  this.type = type;
 }

 class Inner {
  private String type;

  public String getType() {
   return type;
  }

  public void setType(String type) {
   this.type = type;
  }

 }
}

      內部類的意義
                 簡單看來內部類好像就是一種代碼隱藏機制:將類至於其他類的內部.不過內部類遠不止這樣

          它了解外部類,能夠和外部類進行必要的通信。

                  1、封裝一些別人不想知道的操作.

                  2、內部類可以訪問創建它的外部類對象的內容,甚至包括了private的變量.

            內部類同樣可以實現接口,繼承基類,這使得java中的多繼承變得完整.。我們可以使用內部類

            的方式模擬出多繼承的效果。

                 通過內部類繼承基類,外部類創建內部類對象,並使用內部類提供的方法,這樣就變相的實現了

           多繼承的效果.

[java]
public class Graduate{   
    
    private Graduate_stu  gaduate_stu= new Graduate_stu();   
    
    private Graduate_emp  graduate_emp = new Graduate_emp();   
    
    private class Graduate_stu  extends Student{   
    
         public void getName() {   
            ....  
        }   
    }   
    
    private class Graduate_emp extends Employee{   
    
         public double getMoney() 
            { 
                return 0.0; 
             } 
    }   
    
    public void getName() {   
        gaduate_stu.getName();   
    }   
    
    public double getMoney() {   
        graduate_emp .getMoney();   
    }   
}   

public class Graduate{ 
  
    private Graduate_stu  gaduate_stu= new Graduate_stu(); 
  
    private Graduate_emp  graduate_emp = new Graduate_emp(); 
  
    private class Graduate_stu  extends Student{ 
  
         public void getName() { 
            ....
        } 
    } 
  
    private class Graduate_emp extends Employee{ 
  
         public double getMoney()
            {
                return 0.0;
             }
    } 
  
    public void getName() { 
        gaduate_stu.getName(); 
    } 
  
    public double getMoney() { 
        graduate_emp .getMoney(); 
    } 
}              只是用代碼簡單的模擬了一下!
                 內部類還有一個頗具吸引力的特點,那就是內部類和外部類對於接口的繼承是"分離"的

            相互不存在影響的,基於現實的情況,有時候我們實現一個接口,但是接口的方法在此類

            中已經有定義了,對於這種情況,我們就可以使用內部類實現該接口,實現其方法,因為內

           部類對於外部類的成員是可訪問的,因此使用內部類的方法就解決可該問題。

        內部類的分類
                   我們現在知道內部類是放在外部類中的,根據內部類不同的"位置"和特性,內部類可以

             分為以下幾類:

                           ●  成員內部類

                           ●  局部內部類

                           ●  靜態內部類(嵌套類)

 

                           ●  匿名內部類

               對於其具體的特性和用法下面介紹

           成員內部類
             內部類作為外部類的一個成員存在,與外部類的方法,屬性並列.                    

[java]
package com.kiritor; 
public class Outer { 
    private String type="Outer Class"; 
    private static int flag = 1; 
 
    public String getType() { 
        return type; 
    } 
 
    public void setType(String type) { 
        this.type = type; 
    } 
    @Override 
    public String toString() { 
        System.out.println(""+getType()+":"+this.flag); 
        Inner inner = new Inner(); 
        inner.toString();//外部類的非靜態方法訪問內部類的方法  
        //外部類的靜態方法訪問與其是一樣的,不做演示了.  
        return super.toString(); 
    } 
 
    class Inner { 
        private String type="Inner Class"; 
        private   int flag=2;//這裡成員內部類中不允許定義靜態成員  
        public String getType() { 
            return type; 
        } 
 
        public void setType(String type) { 
            this.type = type; 
        } 
        public String toString() { 
            System.out.println(""+getType()+":"+this.flag); 
            System.out.println(""+Outer.this.getType()+Outer.this.flag);//若有變量重名,通過此種方式訪問  
            return super.toString(); 
        } 
         
         
    } 
    public static void main(String[] args) { 
        Outer outer = new Outer(); 
        outer.toString(); 
        Outer.Inner inner = outer.new Inner();//通過此種方式new inner  
        inner.toString(); 
    } 

package com.kiritor;
public class Outer {
 private String type="Outer Class";
 private static int flag = 1;

 public String getType() {
  return type;
 }

 public void setType(String type) {
  this.type = type;
 }
 @Override
 public String toString() {
  System.out.println(""+getType()+":"+this.flag);
  Inner inner = new Inner();
  inner.toString();//外部類的非靜態方法訪問內部類的方法
  //外部類的靜態方法訪問與其是一樣的,不做演示了.
  return super.toString();
 }

 class Inner {
  private String type="Inner Class";
        private   int flag=2;//這裡成員內部類中不允許定義靜態成員
  public String getType() {
   return type;
  }

  public void setType(String type) {
   this.type = type;
  }
  public String toString() {
   System.out.println(""+getType()+":"+this.flag);
   System.out.println(""+Outer.this.getType()+Outer.this.flag);//若有變量重名,通過此種方式訪問
   return super.toString();
  }
  
  
 }
 public static void main(String[] args) {
  Outer outer = new Outer();
  outer.toString();
  Outer.Inner inner = outer.new Inner();//通過此種方式new inner
  inner.toString();
 }
}
            

              Tips:在創建一個內部類的時候除非你已經有了一個外部類對象,否則不可能生成

                 方法內部類對象,因為內部類對象會悄悄的鏈接到創建他的外部類的對象,沒有外部類對象

             自然也就不可能生成內部類對象了,不過還需注意的是內部類是一個在編譯時的概念,一旦編譯

             通過,就會成為完全不同的兩個類,也就是會出現Outer,class和Outer$Inner,class兩個字節碼

             文件。

          

              局部內部類
                   在方法中定義的內部類稱為局部內部類.它與局部變量類似,因此局部內部類是不能有訪問

           修飾符的,因為它不是外部類成員,但是他可以訪問當前方法中的代碼塊的常量,和外部類的所有

          成員.

[java]
package com.kiritor; 
 
public class Outer { 
    private String type = "Outer Class"; 
    private static int flag = 1; 
 
    public String getType() { 
        return type; 
    } 
 
    public void setType(String type) { 
        this.type = type; 
    } 
 
    @Override 
    public String toString() { 
        System.out.println("" + getType() + ":" + this.flag); 
        return super.toString(); 
    } 
 
    public void innerInfo() { 
        final String innerFinal = "可以訪問方法體內的常量"; 
        class Inner { 
            private String type = "Inner Class"; 
            private int flag = 2;// 這裡成員內部類中不允許定義靜態成員  
 
            public String getType() { 
                return type; 
            } 
 
            public void setType(String type) { 
                this.type = type; 
            } 
 
            public String toString() { 
                System.out.println("" + getType() + ":" + this.flag 
                        + innerFinal); 
                System.out.println("" + Outer.this.getType() + Outer.this.flag);// 若有變量重名,通過此種方式訪問  
                return super.toString(); 
            } 
 
        } 
        new Inner().toString();//注意是通過這種方式調用內部類的方法的!  
    } 
 
    public static void main(String[] args) { 
        Outer outer = new Outer(); 
        outer.toString(); 
        outer.innerInfo(); 
    } 

package com.kiritor;

public class Outer {
 private String type = "Outer Class";
 private static int flag = 1;

 public String getType() {
  return type;
 }

 public void setType(String type) {
  this.type = type;
 }

 @Override
 public String toString() {
  System.out.println("" + getType() + ":" + this.flag);
  return super.toString();
 }

 public void innerInfo() {
  final String innerFinal = "可以訪問方法體內的常量";
  class Inner {
   private String type = "Inner Class";
   private int flag = 2;// 這裡成員內部類中不允許定義靜態成員

   public String getType() {
    return type;
   }

   public void setType(String type) {
    this.type = type;
   }

   public String toString() {
    System.out.println("" + getType() + ":" + this.flag
      + innerFinal);
    System.out.println("" + Outer.this.getType() + Outer.this.flag);// 若有變量重名,通過此種方式訪問
    return super.toString();
   }

  }
  new Inner().toString();//注意是通過這種方式調用內部類的方法的!
 }

 public static void main(String[] args) {
  Outer outer = new Outer();
  outer.toString();
  outer.innerInfo();
 }
}

          靜態內部類(嵌套類)
                 前面兩種內部類和變量類似,這裡的變量就是成員變量,和局部變量,可以參照進行對比

              如果你不需要內部類對象與其外部類對象之間有聯系,那你可以將內部類聲明為static的,這就

              是靜態內部類.我們需要明白的是:普通的內部類對象隱含的保存了一個外部類對象的引用。

                   但是當內部類為static的時候這種“特性”也就沒有了,這意味著:

                         1、創建靜態內部類對象的時候並不需要外部類對象

                         2、不能通過靜態內部類對象訪問非靜態的外部類對象了。

              看例子:

[java]
package com.kiritor; 
 
public class Outer { 
    private String type = "Outer Class"; 
    private static int flag = 1; 
 
    public String getType() { 
        return type; 
    } 
 
    public void setType(String type) { 
        this.type = type; 
    } 
 
    @Override 
    public String toString() { 
        System.out.println("" + getType() + ":" + this.flag); 
        Inner.info();//外部類訪問內部類的靜態成員:內部類.靜態成員(靜態方法)  
        Inner inner = new Inner();//這裡生成一個內部類對象不再需要通過外部類對象了  
        inner.toString();//外部類訪問靜態內部類的非靜態成員或方法必須new一個對象  
        System.out.println(inner.type); 
        return super.toString(); 
    } 
 
    static class Inner { 
            private String type = "Inner Class"; 
            private int flag = 2; 
            private static String info="Inner Class 2"; 
            //靜態內部類中可以有非靜態方法、屬性  
            public String getType() { 
                return type; 
            } 
 
            public void setType(String type) { 
                this.type = type; 
            } 
 
            public  static void info() 
            { 
                System.out.println(info); 
            } 
            public String toString() { 
                System.out.println("" + getType() + ":" + this.flag 
                        ); 
                //System.out.println("" + Outer.getType() + Outer.this.flag);// 若有變量重名,通過此種方式訪問  
                return super.toString(); 
            } 
 
        } 
 
    public static void main(String[] args) { 
        Outer outer = new Outer(); 
        outer.toString(); 
         
    } 
}  

package com.kiritor;

public class Outer {
    private String type = "Outer Class";
    private static int flag = 1;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        System.out.println("" + getType() + ":" + this.flag);
        Inner.info();//外部類訪問內部類的靜態成員:內部類.靜態成員(靜態方法)
        Inner inner = new Inner();//這裡生成一個內部類對象不再需要通過外部類對象了
        inner.toString();//外部類訪問靜態內部類的非靜態成員或方法必須new一個對象
        System.out.println(inner.type);
        return super.toString();
    }

    static class Inner {
            private String type = "Inner Class";
            private int flag = 2;
            private static String info="Inner Class 2";
            //靜態內部類中可以有非靜態方法、屬性
            public String getType() {
                return type;
            }

            public void setType(String type) {
                this.type = type;
            }

            public  static void info()
            {
                System.out.println(info);
            }
            public String toString() {
                System.out.println("" + getType() + ":" + this.flag
                        );
                //System.out.println("" + Outer.getType() + Outer.this.flag);// 若有變量重名,通過此種方式訪問
                return super.toString();
            }

        }

    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.toString();
       
    }
}
                可以看出的是:生成一個內部類對象不再需要通過一個外部類對象了,這也是靜態內部類和

        成員內部類的區別:Outer.Inner in = new Outer.Inner();

           匿名內部類

             簡單的說匿名內部類就是沒有名字的類了,這在GUI編程裡面是較為常見的,給個例子:

             

[java]
package com.kiritor; 
 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
 
import javax.swing.JButton; 
import javax.swing.JFrame; 
 
public class MyFrame extends JFrame{ 
    private JButton button = null; 
    public MyFrame() { 
        this.setSize(200, 200); 
        this.setVisible(true); 
        button = new JButton("匿名內部類"); 
        button.addMouseListener(new MouseListener() {//一個匿名的類  
             
            @Override 
            public void mouseReleased(MouseEvent e) { 
                // TODO Auto-generated method stub  
                 
            } 
             
            @Override 
            public void mousePressed(MouseEvent e) { 
                // TODO Auto-generated method stub  
                 
            } 
             
            @Override 
            public void mouseExited(MouseEvent e) { 
                // TODO Auto-generated method stub  
                 
            } 
             
            @Override 
            public void mouseEntered(MouseEvent e) { 
                // TODO Auto-generated method stub  
                 
            } 
             
            @Override 
            public void mouseClicked(MouseEvent e) { 
                // TODO Auto-generated method stub  
                 
            } 
        }); 
        this.add(button); 
         
         
    } 
     

package com.kiritor;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class MyFrame extends JFrame{
 private JButton button = null;
 public MyFrame() {
  this.setSize(200, 200);
  this.setVisible(true);
  button = new JButton("匿名內部類");
  button.addMouseListener(new MouseListener() {//一個匿名的類
   
   @Override
   public void mouseReleased(MouseEvent e) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void mousePressed(MouseEvent e) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void mouseExited(MouseEvent e) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void mouseEntered(MouseEvent e) {
    // TODO Auto-generated method stub
    
   }
   
   @Override
   public void mouseClicked(MouseEvent e) {
    // TODO Auto-generated method stub
    
   }
  });
  this.add(button);
  
  
 }
   
}
          對於匿名內部類,筆者現就不做總結了,之後會找個時間理解一下.

          內部類的相關問題
                    下面討論的是內部類中的一些有趣的問題!

                         內部類能否被"重載"、“繼承”?

               內部類重載問題

                       假設如果你創建了一個外部類,並定義了一個內部類,之後繼承外部類並重新定義內部類

                   的時候會發生什麼呢?

 

[java]
package com.kiritor; 
 
class Outer { 
    public Outer() { 
        System.out.print("Outer:"); 
        new Inner(); 
    } 
 
    class Inner { 
 
        public Inner() { 
            System.out.println("Inner"); 
        } 
 
    } 
 

 
public class Outer2 extends Outer { 
    class Inner { 
 
        public Inner() { 
            System.out.println("outer2:Inner"); 
        } 
    } 
 
    public static void main(String[] args) { 
        new Outer2(); 
 
    } 
 

package com.kiritor;

class Outer {
 public Outer() {
  System.out.print("Outer:");
  new Inner();
 }

 class Inner {

  public Inner() {
   System.out.println("Inner");
  }

 }

}

public class Outer2 extends Outer {
 class Inner {

  public Inner() {
   System.out.println("outer2:Inner");
  }
 }

 public static void main(String[] args) {
  new Outer2();

 }

}
            看一看輸出情況:Outer:Inner
                缺省的構造器Outer2()是編譯器自動生成的,他會先調用父類的構造器,通過結果可以看出

          雖然創建的是子類對象,但是 內部類並不是使用的"重載"過的.這說明檔你繼承了某個外部類

          的時候,內部類並未發生特別變化,當然明確的繼承某個內部類的方式除外!

         

[java]
package com.kiritor; 
 
class Outer { 
    public Outer() { 
        System.out.print("Outer:"); 
        new Inner(); 
    } 
 
    class Inner { 
 
        public Inner() { 
            System.out.println("Inner"); 
        } 
 
    } 
 

 
public class Outer2 extends Outer { 
    class Inner extends com.kiritor.Outer.Inner{ 
 
        public Inner() { 
            System.out.println("outer2:Inner"); 
        } 
    } 
 
    public Outer2() { 
        new Inner(); 
    } 
    public static void main(String[] args) { 
        new Outer2(); 
 
    } 
 

package com.kiritor;

class Outer {
 public Outer() {
  System.out.print("Outer:");
  new Inner();
 }

 class Inner {

  public Inner() {
   System.out.println("Inner");
  }

 }

}

public class Outer2 extends Outer {
 class Inner extends com.kiritor.Outer.Inner{

  public Inner() {
   System.out.println("outer2:Inner");
  }
 }

 public Outer2() {
  new Inner();
 }
 public static void main(String[] args) {
  new Outer2();

 }

}
           明確繼承之後的輸出結果為:

              

         內部類的繼承問題
                有時候我們只是需要繼承內部類,但是內部類的構造器又必須用到外部對象的引用

           , 因此在繼承一個內部類的時候就有點特別了,主要的問題在於外部類對象的引用必須

           初始化,而在被繼承類中並不存在,也就是單一繼承內部類的時候,沒有內部類與其外部類

           的一種關聯.

               可以使用一下方式解決:

      

[java]
package com.kiritor; 
 
import com.kiritor.Outer.Inner; 
 
class Outer { 
    public Outer() { 
        System.out.print("Outer:"); 
        new Inner(); 
    } 
 
    class Inner { 
 
        public Inner() { 
            System.out.println("Inner"); 
        } 
 
    } 
 
 

 
public class Inner2 extends Outer.Inner { 
  Inner2(Outer outer) 
   { 
       outer.super(); 
       //構造器只能是這種方式的  
       System.out.println("只能為此種構造器"); 
   } 
  
public static void main(String[] args) { 
    new Inner2(new Outer()); 

package com.kiritor;

import com.kiritor.Outer.Inner;

class Outer {
 public Outer() {
  System.out.print("Outer:");
  new Inner();
 }

 class Inner {

  public Inner() {
   System.out.println("Inner");
  }

 }

}

public class Inner2 extends Outer.Inner {
  Inner2(Outer outer)
   {
    outer.super();
    //構造器只能是這種方式的
    System.out.println("只能為此種構造器");
   }
 
public static void main(String[] args) {
 new Inner2(new Outer());
}
}
      輸出結果為:

          Outer:Inner
           Inner
          只能為此種構造器
        可以看出的是,Inner2只是集成了內部類,但是其缺省的構造器並不能用,而且僅僅傳遞一個

    外部類的引用還不夠,還必須首先調用外部類的構造方法.這樣才提供了內部類與外部類對象

    的引用關聯,才能夠通過編譯的.

 

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved