討論Java中的內部類是什么?


前言

內部類,講完前面的特性,今天就講下內部類這個用的比較多,出現頻率挺高的知識點。

what is that?

首先,顧名思義,內部類就是在類的內部,也就是類的類,嵌套在里面的。直接代碼介紹,現一般分為成員內部類和局部內部類,還有一種匿名類。內部類擁有對外圍對象的引用。大部分使用的都是成員內部類。成員內部類是一種與Field、方法、構造器和初始化塊相似的類成員;局部內部類和匿名內部類則不是類成員。

成員內部類

定義在類里面的成員變量域的類,就是成員內部類。此時的內部類作為其外部類的成員,所以可以使用任意訪問控制符如private、protected和public等修飾。

class A {
    //成員內部類,這種包含類的結構
	class b{}
}

成員內部類還可以分為靜態內部類和非靜態內部類。注意:根據靜態成員不能訪問非靜態成員的規則,外部類的靜態方法、靜態代碼塊不能訪問非靜態內部類,包括不能使用非靜態內部類定義變量、創建實例等。

  • 靜態內部類(帶static)

static關鍵字的作用是把類的成員變成類相關,而不是實例相關,即static修飾的成員屬於整個類,而不屬於單個對象。靜態內部類只可以訪問靜態的外部類的方法和對象。但是靜態內部類可以有非靜態成員。

/**
 * 這一篇是用來測試靜態內部類的使用的
 * @author yhy
 * @date 1/14
 */
public class StaticInner {
    private  int num = 7;

    /**
     *  定義靜態常量,這個才可以被靜態內部類調用
     */
    private  static  int num2 = 6;
    static class Innerclass{
        private static int num3;
        public void innerfangfa(){
//          System.out.println("調用外部類的成員變量:"+num);,這個會報錯,因為不能調用非靜態的 
            System.out.println("調用外部類的成員變量:"+num2);
        }
    }
}

報錯信息

外部類使用靜態類的代碼。

public class StaticInner {
    private  int num = 7;

    /**
     *  定義靜態常量,這個才可以被靜態內部類調用
     */
    private  static  int num2 = 6;

    /**
     * 定義一個靜態內部類
     */
    static class Innerclass{
        private static int num3;
        private int num4 = 4;
        public void innerfangfa(){
//          System.out.println("調用外部類的成員變量:"+num);,這個會報錯,因為不能調用非靜態的
            System.out.println("調用外部類的成員變量:"+num2);
        }
    }

    /**
     * 這是外部類的方法,用來驗證訪問內部類的方法
     */
    public static void inneracess(){
//        通過類名訪問靜態內部類的類成員
        System.out.println("訪問靜態內部類:"+Innerclass.num3);
//        通過實例訪問靜態內部類的實例成員
        System.out.println("訪問靜態內部類:"+new Innerclass().num4);

    }
}
  • 非靜態內部類(不帶static)

內部類可以直接訪問外部類的變量、方法等,而外部類只能通過顯式創建類才可以。包括可以訪問外部類的private。同時,在非靜態內部類里不能有靜態方法、靜態field、靜態初始化塊。

/**
 * 這一篇是用來講內部類的一些定義的
 * @author yhy
 * @date 1/14
 */
public class InnerClass {
    private int outernum = 9;

    /**
     * 創建內部類,同時還定義一個常量,為private
     */
    class Inner{
        private  int innernum = 8;
//        定義內部類的方法,去調用外部類的成員常量
        public void outAcess(){
            System.out.println("外部類的值:"+outernum);
        }
    }

    /**
     * 這個是外部類的成員方法
     * 這里直接調用內部類會報錯,不可以直接innernum使用
     * 要通過顯式創建內部類對象才可以實現
     */
    public void innerAcess(){
        System.out.println("內部類的值:"+new Inner().innernum);

    }
    public static void main(String[] args) {
//        創建外部類對象,沒創建內部類對象
     InnerClass i = new InnerClass();
        i.innerAcess();
   
    }

}
//非靜態內部類對象必須寄存在外部類對象里,而外部類對象則不必一定有非靜態內部類對象寄存其中

非靜態內部類的方法內訪問某個變量時,系統優先在該方法內查找(如果存在就使用)——if not,則到該方法所在的內部類中(存在則使用)——if not,則到該內部類所在的外部類(如果存在則使用)——if not,系統將出現編譯錯誤。

局部內部類

局部內部類是定義在類的內部方法或者其他作用域里面的內部類。

class A {
	//局部內部類
	public void B(){
		class B{}
	}
}

局部內部類的使用

package music.daima.ebook;
 /**
 *  * 這一篇是用來觀察局部內部類的定義使用等,thinking in java的練習九
 *  * @author yhy
 *  * @date 1/14
 *  */

 interface  Ex9Interface{
     /**
      * @param s string類型在下面給內部類調用
      * 定義一個接口,同時包含一個say方法,給下面使用
      */
     void say(String s);
 }
public class JuBuInner {
     /**
      * @return Inner()返回該類對此接口的引用
      * //    這是一個方法,下面在里面定義一個內部類
      */

    Ex9Interface f() {
        class Inner implements Ex9Interface {
            @Override
            public void say(String s) {
                System.out.println(s);
            }
        }
        return new Inner();
    }
    public static void main(String[] args) {
       JuBuInner x = new JuBuInner();
//       調用局部內部類的say方法
        x.f().say("hi");
    }
}

  • 局部內部類不可以為publicprivate來修飾。而且因為它的上一級是方法,所以用static來修飾它是沒有意義的,所以也不能用static來修飾

匿名內部類

這個知識點就直接看代碼,是內部類的簡化寫版 ,本質不是類而是匿名對象(繼承該類或者實現了改接口的)。

前提

得提前存在一個類或者是接口給它用,可以是具體類也可以是抽象類。

格式

new 類名or接口名() {重寫方法};

package music.daima.ebook;
/**
 * thinking in java
 * @author yhy
 * 匿名內部類
 */
public class AnonymousInner {
    public static test1 getTest(int i){
//        匿名類的結構如下,這里的i會傳給基類的構造器
        return new test1(i) {
            {
                System.out.println(22);
            }
//            重寫f方法
            @Override
            public void f() {
                System.out.println("在匿名類內");
            }
        };//這里要注意有分號
    }
    public static void main(String[] args) {
        test1 abc = getTest(55);
        abc.f();
    }
}

/**
 *創建一個抽象類
 */
abstract class test1{
//    基類的構造器
    public test1(int i){
        System.out.println("i is :"+i);
    }
    public abstract void f();
}

《Java的編程思想》中的練習題答案——使用匿名內部類

interface Inner12 {
	void modifyOuter();
}

public class Outer12 {
	private int oi = 1;
	private void hi() { System.out.println("Outer hi"); }
	public Inner12 inner() {
		return new Inner12() {
			public void modifyOuter() { 
				oi *= 2;
				hi(); 
			}
		}; 
	}
	public void showOi() { System.out.println(oi); }
	public static void main(String[] args) {
		Outer12 out = new Outer12();
		out.showOi();
		out.inner().modifyOuter();
		out.showOi();
	}
}

下面的pd.method()方法調用結果是一樣的,下面用的就是匿名內部類,相對簡單一點,但是不好理解。記住它是一個對象而不是類。

why use it?

  1. 內部類方法可以訪問該類定義所在的作用域中的數據,包括私有的數據

  2. 內部類可以對同一個包內的其他類隱藏起來

  3. 當想要定義一個回調函數且不想編寫大量代碼,可以考慮使用匿名內部類比較便捷

    ​ ——《Java核心技術卷一》

個人理解:

  • 內部類可以將其封裝起來,很好的隱藏,可以用protected 和private權限來修飾。
  • 擁有訪問外部類的所有元素的權限,普通的內部類對象隱式地保存了一個引用,指向創建它的外圍類對象。
  • 比如可以很好處理類的辦法同名重疊情況,更加有效地去引用。
  • 可以間接實現了多重繼承,內部類繼承其它類,然后實例化外部類可以實現這種間接效果

how to use?

1.在外部類以外使用靜態內部類

(因為靜態內部類是外部類類相關的,因此創建內部類對象時無須創建外部類對象。)

/**這是用來測試在外部類以外使用靜態內部類
 * @author yhy
 */
public class innerOut {
    public static void main(String[] args) {
        Out1.In1 abc = new Out1.In1();
    }
}

/**
 * 定義一個外部類
 * @author yhy
 */
class Out1{
    /**
     * 定義一個靜態內部類,靜態內部類是直接與外部類相關的
     */
    static class In1{
        void FangFa(){
            System.out.println("這是靜態內部類");
        }
    }
}
//output:這是靜態內部類

2.在外部類以外使用非靜態內部類

/**
 * 使用教程——外部類以外使用非靜態內部類
 * @author yhy
 */
public class InnerTest {
    public static void main(String[] args) {
//        格式,先外部再內部 = new 外部.new 內部
        Out.In test = new Out().new In();
        test.inner();
        
    }
}
/**
 * 定義一個外部類
 */
class Out{
    /**
     * 定義一個非靜態內部類
     */
    class In{
        void inner(){
            System.out.println("打印出內部類的信息");
        }
    }
}
//output:打印出內部類的信息

3.在外部類內部使用內部類

在上面有使用的代碼

總結

靜態內部類和非靜態內部類區別只是在創建內部類對象時,靜態的只需使用外部類即可調用構造器,而非靜態則一定使用外部類對象來調用里面的方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM