深入理解java巢狀類和內部類、匿名類
深入理解java巢狀類和內部類、匿名類
可以在一個類的內部定義另一個類,這種類稱為巢狀類(nested classes),它有兩種型別:靜態巢狀類和非靜態巢狀類。靜態巢狀類使用很少,最重要的是非靜態巢狀類,也即是被稱作為內部類(inner)。巢狀類從JDK1.1開始引入。其中inner類又可分為三種:
其一、在一個類(外部類)中直接定義的內部類;
其二、在一個方法(外部類的方法)中定義的內部類;
其三、匿名內部類。
下面,我將說明這幾種巢狀類的使用及注意事項。
如下所示程式碼為定義一個靜態巢狀類,
- 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";//內部類公有成員
- public void display(){
- //System.out.println(id);//不能直接訪問外部類的非靜態成員
- System.out.println(name);//只能直接訪問外部類的靜態成員
- System.out.println("Inner "+address);//訪問本內部類成員。
- }
- }
- public void 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);//可以訪問內部類的公有成員
- }
- public static void main(String[] args) {
- StaticTest staticTest = new StaticTest();
- staticTest.printInfo();
- }
- }
在靜態巢狀類內部,不能訪問外部類的非靜態成員,這是由Java語法中"靜態方法不能直接訪問非靜態成員"所限定。若想訪問外部類的變數,必須通過其它方法解決,由於這個原因,靜態巢狀類使用很少。注意,外部類訪問內部類的的成員有些特別,不能直接訪問,但可以通過內部類來訪問,這是因為靜態巢狀內的所有成員和方法預設為靜態的了。同時注意,內部靜態類Person只在類StaticTest 範圍內可見,若在其它類中引用或初始化,均是錯誤的。
如下所示程式碼為在外部類中定義兩個內部類及它們的呼叫關係:
- public class Outer {
- int outer_x = 100;
- class Inner{
- 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);
- }
- }
- 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();
- 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 static void main(String args[]){
- Outer outer = new Outer();
- outer.test();
- }
- }
以上程式碼需要說明有,對於內部類,通常在定義類的class關鍵字前不加public 或 private等限制符,若加了沒有任何影響,同時好像這些限定符對內部類的變數和方法也沒有影響(?)。另外,就是要注意,內部類Inner及InnterTwo只在類Outer的作用域內是可知的,如果類Outer外的任何程式碼嘗試初始化類Inner或使用它,編譯就不會通過。同時,內部類的變數成員只在內部內內部可見,若外部類或同層次的內部類需要訪問,需採用示例程式中的方法,不可直接訪問內部類的變數。
四、在外部類中定義內部類
匿名類就是沒有名字的內部類,是內部類的一種特殊情況。????????? 這句話對嗎???
前端時間在寫.net專案中,一直錯將.cs裡的兩個class當作內部類,原來是一個檔案裡的兩個類而已,這讓我想起了Java中的內部類,比較內部類,那麼還有兩個類,那就是匿名類和匿名內部類。今天我想就Java中的這三種類進行個比較。
我們知道在Java語言規範中可以做很多事,例如一個類或一個介面中可以宣告一個類或介面,在一個方法中可以宣告一個類,類與介面宣告可以巢狀任意深度等。
匿名類:
1、new <類或介面><類的主體>,匿名類的宣告是在編譯時進行的,例項化是在執行時進行的,所以在for迴圈中一個new語句會建立相同匿名類的幾個例項,而不是建立幾個不同匿名類的一個例項。
2、如果要執行的物件需要一個物件,但卻不值得建立全新的物件(可能是因為該物件只在一個方法內部使用),在這個時候使用匿名類就會非常合適,所以說,匿名類一般會在swing程式中快速建立事件處理程式。
- firstButton.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- getTxtValue().setText("第一個按鈕觸發的事件!");
- }
- });
3、從技術上說,匿名類可以被看作非靜態的內部類,所以他們具有方法內部宣告的非靜態內部類相同的許可權和限制。
內部類:
內部類顧名思義就是在一個類的內部還有一個類
- package com.iflytek.innerclass;
- /**
- * @author xudongwang 2012-1-11
- *
- * Email:xdwangiflytek@gmail.com
- */
- public class InnerClassDemo {
- public static void main(String[] args) {
- new Outer().fun();
- }
- }
- class Outer {
- private String name = "Hello 內部類";
- class Inner {
- public void print() {
- System.out.println("name = " + name);
- }
- };
- public void fun() {
- new Inner().print();
- }
- }
內部類生成的.class檔名為:Outer$Inner.class,從上面的結構發現內部類的的缺點是“結構非常的混亂”。
- package com.iflytek.innerclass;
- /**
- * @author xudongwang 2012-1-11
- *
- * Email:xdwangiflytek@gmail.com
- */
- public class InnerClassDemo02 {
- public static void main(String[] args) {
- new Outer02().fun();
- }
- }
- class Outer02 {
- private String name = "Hello 內部類";
- public void fun() {
- new Inner02(this).print();
- }
- public String getName() {
- return this.name;
- }
- };
- class Inner02 {
- private Outer02 out;
- public Inner02(Outer02 out) {
- this.out = out;
- }
- public void print() {
- System.out.println("name = " + this.out.getName());
- }
- };
從上可以看出內部類的優點是“可以方便的訪問外部類中的私有成員”;
如果要在外部直接使用內部類的例項化物件:
外部類.內部類 內部類物件 = 外部類例項.new 內部類例項();
- package com.iflytek.innerclass;
- /**
- * @author xudongwang 2012-1-11
- *
- * Email:xdwangiflytek@gmail.com
- */
- public class InnerClassDemo03 {
- public static void main(String[] args) {
- Outer03 out = new Outer03();//外部類例項
- Outer03.Inner inner = out.new Inner();//例項化內部類物件
- inner.print();
- }
- }
- class Outer03{
- private String name = "Hello 內部類";
- class Inner {
- public void print() {
- System.out.println("name = " + name);
- }
- }
- }
一個內部類如果使用static關鍵字宣告的話,則此內部類就將成為外部類,可以直接通過外部類.內部類的形式訪問
- package com.iflytek.innerclass;
- /**
- * @author xudongwang 2012-1-11
- *
- * Email:xdwangiflytek@gmail.com
- */
- public class InnerClassDemo04 {
- public static void main(String[] args) {
- Outer04.Inner inner = new Outer04.Inner();// 例項化內部類物件
- inner.print();
- }
- }
- class Outer04 {
- private static String name = "Hello 內部類";
- static class Inner {
- public void print() {
- System.out.println("name = " + name);
- }
- }
- }
內部類可以在任意的地方使用,例如方法中宣告
- package com.iflytek.innerclass;
- /**
- * @author xudongwang 2012-1-11
- *
- * Email:xdwangiflytek@gmail.com
- */
- public class InnerClassDemo05 {
- public static void main(String[] args) {
- new Outer05().fun();
- }
- }
- class Outer05 {
- private static String name = "Hello 內部類";
- public void fun() {
- class Inner {
- public void print() {
- System.out.println("name = " + name);
- }
- }
- new Inner().print();
- }
- }
在方法中定義的內部類,可以直接訪問外部類中的各個成員,但是如果要訪問方法中的引數,則需要在引數上加上final關鍵字宣告;
- package com.iflytek.innerclass;
- /**
- * @author xudongwang 2012-1-11
- *
- * Email:xdwangiflytek@gmail.com
- */
- public class InnerClassDemo06 {
- public static void main(String[] args) {
- new Outer06().fun(20);
- }
- }
- class Outer06 {
- private static String name = "Hello 內部類";
- public void fun(final int temp) {
- class Inner {
- public void print() {
- System.out.println("temp = " + temp);
- System.out.println("name = " + name);
- }
- }
- new Inner().print();
- }
- }
匿名類與內部的聯絡與區別:
按所在位置可以分為兩大類:
1、在類的方法中
特點:
a、可以訪問宿主類的所有元素 ;
b、儲存宿主類物件的引用,建立物件時必須有宿主類物件;
c、 不能有靜態資料;
繼續劃分:
A、本地內部類;
B、匿名內部類
兩者的區別在於本地內部類有構造方法,而匿名內部類只能例項初始化;
2、在類或介面作用域中;
繼續劃分:
A、普通內部類
B、靜態內部類
匿名內部類:
匿名內部類是在抽象類和介面的基礎之上發展起來的。
- package com.iflytek.innerclass;
- /**
- * @author xudongwang 2012-1-11
- *
- * Email:xdwangiflytek@gmail.com
- */
- public class NoNameClass01 {
- public static void main(String[] args) {
- new X().fun2();
- }
- }
- interface A {
- public void fun();
- }
- class B implements A {
- public void fun() {
- System.out.println("Hello 準備匿名內部類");
- }
- }
- class X {
- public void fun1(A a) {
- a.fun();
- }
- public void fun2() {
- this.fun1(new B());
- }
- }
通過上面的Demo,如果現在假設B類只使用一次,那麼還有必要將其定義成一個單獨的類麼?
呵呵,此時就可以使用匿名內部類:
- package com.iflytek.innerclass;
- /**
- * @author xudongwang 2012-1-11
- *
- * Email:xdwangiflytek@gmail.com
- */
- public class NoNameClass02 {
- public static void main(String[] args) {
- new XX().fun2();
- }
- }
- interface AA {
- public void fun();
- }
- class XX {
- public void fun1(AA a) {
- a.fun();
- }
- public void fun2() {
- this.fun1(new AA() {
- public void fun() {
- System.out.println("Hello 準備匿名內部類");
- }
- });
- }
- }
其實在真正的專案開發中匿名內部類使用的非常之少,一般在Java的圖形介面和現在的Android中使用的比較多點。
最後給一個內部類實現的簡單連結串列:
- package com.iflytek.innerclass;
- /**
- * @author xudongwang 2012-1-11
- *
- * Email:xdwangiflytek@gmail.com
- */
- public class LinkDemo {
- public static void main(String args[]) {
- Link link = new Link();
- link.add("A");
- link.add("B");
- link.add("C");
- link.add("D");
- link.add("E");
- link.print();
- }
- };
- class Link {
- class Node {
- private String name;
- private Node next; // 單向連結串列,每個節點指向下一個節點
- public Node(String name) {
- this.name = name; // 通過構造方法為name屬性賦值
- }
- public void addNode(Node newNode) { // 增加節點
- if (this.next == null) {
- this.next = newNode; // 儲存節點
- } else {
- this.next.addNode(newNode); // 繼續向下查詢
- }
- }
- public void printNode() { // 輸出節點
- System.out.println(this.name);
- if (this.next != null) { // 此節點之後還存在其他的節點
- this.next.printNode();
- }
- }
- };
- private Node root; // 連結串列的頭
- public void add(String name) { // 增加節點
- Node newNode = new Node(name); // 定義一個新的節點
- /*
- * 如果是第一個節點,則肯定是根節點, 如果是第二個節點,則肯定放在根節點next中 如果是第三個節點,則肯定放在第二個節點的next中
- */
- if (this.root == null) {
- this.root = newNode; // 將第一個節點設定成根節點
- } else {
- // 肯定要放在最後一個節點之後
- // 通過節點.next來不斷的判斷
- this.root.addNode(newNode);
- }
- }
- public void print() {
- if (this.root != null) { // 如果根節點為空了,則沒有任何內容
- this.root.printNode();
- }
- }
- };
相關文章
- Java中的巢狀類、內部類、靜態內部類Java巢狀
- Java內部類和匿名內部類的用法Java
- 匿名內部類理解
- 介紹巢狀類和內部類(轉)巢狀
- Java類與匿名內部類Java
- Java內部類詳解--匿名內部類Java
- java內部類之成員內部類之匿名內部類Java
- java內部類,區域性內部類,靜態內部類,匿名內部類Java
- Java測試內部類和巢狀類位置的合法性Java巢狀
- 10-Java內部類——成員內部類、區域性內部類、匿名內部類Java
- Kotlin基礎 — 巢狀類、內部類Kotlin巢狀
- java之內部類(InnerClass)----非靜態內部類、靜態內部類、區域性內部類、匿名內部類Java
- 匿名內部類
- Java基礎10---包、內部類、匿名內部類Java
- Java的特殊類用法:檔案類、內部類、本地類、匿名類Java
- Java中的匿名內部類及內部類的二三事Java
- Android筆記之Kotlin、Java的內部類?巢狀類?Android筆記KotlinJava巢狀
- java培訓教程:什麼是匿名內部類?怎樣建立匿名內部類?Java
- java匿名內部類:“ 儂好,世界”Java
- Java基礎8:深入理解內部類Java
- java內部類的理解Java
- 匿名內部類泛型泛型
- Kotlin——中級篇(七):抽象類(abstract)、內部類(巢狀類)詳解Kotlin抽象巢狀
- java中的匿名內部類總結Java
- Java_介面回撥與匿名內部類Java
- Java之區域性匿名內部類物件Java物件
- java內部類之成員內部類Java
- 使用內部和匿名類最佳化Java程式碼(轉)Java
- Java和ABAP裡的外部類和內部類Java
- java內部類之成員內部類之區域性內部類Java
- 關於java匿名內部類初始化法Java
- 用匿名內部類實現 Java 同步回撥Java
- Java 內部類Java
- Java內部類Java
- Java內部類詳解-- 成員內部類Java
- java內部類,為什麼需要內部類?Java
- Java進階07 巢狀類Java巢狀
- Java巢狀類(NestedClasses)總結Java巢狀