Thinking in Java之內部類__Java

來源:互聯網
上載者:User
        前言

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

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

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

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

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

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

          外部類只能使用public和預設的包存取權限.

            若非這兩種編譯出錯: 

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

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中的多繼承變得完整.。我們可以使用內部類

            的方式類比出多繼承的效果。

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

           多繼承的效果.

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();      }  }  
            只是用代碼簡單的類比了一下!
                 內部類還有一個頗具吸引力的特點,那就是內部類和外部類對於介面的繼承是"分離"的

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

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

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

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

             分為以下幾類:

                           ●  成員內部類

                           ●  局部內部類

                           ●  靜態內部類(嵌套類)

                           ●  匿名內部類

               對於其具體的特性和用法下面介紹            成員內部類

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

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;}@Overridepublic 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 innerinner.toString();}}
            

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

                 方法內部類對象,因為內部類對象會悄悄的連結到建立他的外部類的對象,沒有外部類對象

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

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

             檔案。

                         局部內部類

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

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

          成員.

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;}@Overridepublic 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、不能通過靜態內部類對象訪問非靜態外部類對象了。

              看例子:

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編程裡面是較為常見的,給個例子:

             

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() {//一個匿名的類@Overridepublic void mouseReleased(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mousePressed(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseExited(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseEntered(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseClicked(MouseEvent e) {// TODO Auto-generated method stub}});this.add(button);}    }
          對於匿名內部類,筆者現就不做總結了,之後會找個時間理解一下.

          內部類的相關問題

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

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

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

                   的時候會發生什麼呢?

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()是編譯器自動產生的,他會先調用父類的構造器,通過結果可以看出

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

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

         

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;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隻是整合了內部類,但是其預設的構造器並不能用,而且僅僅傳遞一個

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

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

     

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.