日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 内部类详解

發布時間:2024/3/12 java 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 内部类详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

內部類

一個定義在另一個類中的類,叫作內部類

1. 概述

內部類允許你把一些邏輯相關的類組織在一起,并控制位于內部的類的可見性,這么看來,內部類就像是一種代碼隱藏機制:將類置于其他類的內部,從而隱藏名字與組織代碼的模式。

2. 創建內部類

創建內部類的方式就如同你想的一樣,把類的定義置于外部類里面

public class Outer {// 其他一些成員聲明...public class Inner {// 其他一些成員聲明...} }

3. 鏈接外部類

內部類與其外部類之間存在一種聯系,通過這個聯系可以訪問外部類的所有成員,而不需要任何特殊條件,可以這么說,內部類擁有其外部類的所有元素的訪問權。

這是如何做到的呢?當某個外部類的對象創建一個內部類對象時,該內部類對象會秘密地捕獲一個指向外部類對象的引用。在你訪問外部類成員時,可以通過這個引用選擇外部類的成員。所有這些實現的細節由編譯器幫忙處理,大多數時候都無需程序員關心。

4. 使用 .this 和 .new

如果你需要生成對外部類對象的引用,可以使用外部類的名字后面緊跟圓點和 this

public class Outer {public class Inner {public Outer getOuter() {return Outer.this;}}public static void main(String[] args) {Outer outer = new Outer();Outer outer2 = outer.getOuter();} }

如果你想創建某個內部類對象,必須在 new 表達式中提供其外部類的引用,這時需要使用 .new 語法

public class Outer {public class Inner {}public static void main(String[] args) {Outer outer = new Outer();Outer.Inner inner = outer.new Inner();} }

如果從外部類的非靜態方法之外的位置創建某個內部類對象,要具體指明這個內部類對象的類型:OuterClassName.InnerClassName(在外部類的靜態方法中也可以直接指明類型 InnerClassName)

5. 向上轉型

當將內部類向上轉型為其基類(接口),可以很方便地隱藏實現細節,因為外界所得到的只是指向基類或接口的引用。

// 這是一個接口 public interface Content {...}class Outer {// 注意這里將訪問修飾符設為 privateprivate class PContent implements Content {...}public Content getContent() {return new PContent();} }

在 Outer 類中,內部類 PContent 是私有的,除了 Outer 外沒有人可以訪問。這意味著,客戶端程序員如果想了解這些內部類成員,那是要受限制的。客戶端程序員無法訪問任何新增的、不屬于公共接口的方法,也不能向下轉型,因為不能訪問其名字。

6. 多重嵌套內部類

無論一個內部類被嵌套多少層,它都能透明地訪問所有它所嵌入的外部類的所有成員

class MNA {private void f() {}class A {private void g(){}public class B {void h() {g();f();}}} }public class TestClass {public static void main(String[] args) {MNA mna = new MNA();MNA.A mnaa = mna.new A();MNA.A.B mnaab = mnaa.new B();mnaab.h();} }

成員內部類

成員內部類是最普通的內部類,它和外部類的成員變量一樣,定義在類的內部,可以聲明訪問修飾符。成員內部類有如下特性:

  • 不可以定義靜態成員和方法,因為內部類是外部類的一個成員,只有當外部類初始化時,內部類才能初始化,靜態變量屬于類級別,在類加載的時候就初始化,所以兩者本身在語法上就有矛盾。但可以定義常量。
  • 可以無條件訪問外部類的所有成員屬性和成員方法(包括 private 成員和靜態成員)。當成員內部類擁有和外部類同名的成員變量或者方法時,會發生隱藏現象,即默認情況下訪問的是成員內部類的成員。如果要訪問外部類的同名成員,需要以下面的形式進行訪問:OuterClassName.this.innerClassMember

局部內部類

在方法的作用域內(而不是在其他類的作用域內)創建一個完整的類,這個類被稱作局部內部類。由于是定義在方法內,所以不能聲明訪問修飾符,作用范圍僅在聲明類的代碼塊中,但這并不意味著一旦方法作用域執行完畢,局部內部類就不可用了。局部內部類有如下特性:

  • 局部內部類同樣不可以定義靜態成員和方法
  • 可以無條件訪問外部類的所有成員屬性和成員方法,但不能訪問方法體內的局部變量,除非定義為 final 常量(仔細想想就知道了,內部類是依靠對外部類的引用進行訪問的)
public class Outer {public Outer method() {class Inner {...} } }

匿名內部類

只用一次的沒有名字的類,具體看下面的例子:

public class Outer {public Content method() {return new Content() {private int i = 11;@Overridepublic int getValue() {return i}}} }

這種奇怪的語法指的是:創建一個繼承自 Content 的匿名類的對象。通過 new 表達式返回的這個引用被自動向上轉型為 Content 的引用。上述匿名內部類是下述形式的一種簡化形式,也就是說,匿名內部類可以看作對成員內部類或局部內部類的一種簡寫:

public class Outer {class MyContent implements Content {private int i = 11;@Overridepublic int getValue() {return i}}public Content method() {return new MyContent();} }

匿名內部類沒有構造器(因為它根本沒有名字),如果我們希望為匿名內部類做一些初始化操作,那該怎么辦呢?如果該匿名內部類的基類構造器有參數,則可以直接使用,但編譯器會要求其參數引用是 final(即使你不加,Java8 也會為我們自動加上 final)。或者通過代碼塊,模仿構造器的行為來實現初始化。

public class Outer {public Content method() {return new Content(final int a, final int b) {private int i = a;private int j;{j = b;}}} }

靜態內部類

如果不需要內部類對象與其外部類對象之間有聯系,可以將內部類聲明為 static。既然靜態內部類不需要與外部類有聯系,那么也就沒有指向外部類的 this 引用,更像一個獨立的類,這意味著:

  • 要創建靜態內部類的對象,并不需要其外部類的對象
  • 不能訪問非靜態的外部類對象,只能訪問外部類中的 static 所修飾的成員變量或者是方法
public class Outer {public static class Inner {private String label;public String method1() {...}static int x = 10;public static void method2() {...}} }

靜態內部類可以作為接口的一部分,因為你放到接口中的任何類都自動是 public 和 static 的,甚至可以在內部類中實現其外部類接口。

public interface ClassInterface {void method1();class InnerClass implements ClassInterface {@Overridepublic void method1() {...}} }

為什么需要內部類?

內部類的第一個用途就是可以操作創建它的外部類的對象,典型的例子就是集合中常使用的迭代器 iterator。這只是其中之一,使用內部類最吸引人的原因莫過于:

每個內部類都能獨立地繼承自某個類或實現某個接口,無論外部類是否繼承了某個類或實現某個接口

基于這個特性,使得多重繼承成為可能,我們可以讓多個內部類以不同的方式實現不同的接口,或繼承不同的類。下面這個例子使用了匿名內部類,可能你們已經習以為常,但別忘了匿名內部類其實就是內部類的一種簡寫形式。

class D {}abstract class E {}class Z extend D {E getE() {return new E() {};} }public class TestClass {static void setD(D d){}static void setE(E e){}public static void main(String[] args) {Z z = new Z();setD(z);setE(z.getE);} }

另外,內部類也是實現回調的絕佳選擇。通過內部類可以實現一個閉包,所謂閉包就是一個可調用的對象,它記錄了一些信息。在需要提供閉包來實現回調時,我們可以采用匿名內部類的方式。


繼承內部類

因為內部類的構造器必須連接到其外部類對象的引用,所以在繼承內部類時,那個指向外部類對象的引用必須被初始化,而在派生類中又不再存在這個引用了。要解決這個問題,必須使用特殊的語法來明確說清它們之間的關系。

class WithInner {class Inner {} }public class InheritInner extends WithInner.Inner {InheritInner(WithInner wi) {wi.super();}public static void main(String[] args) {WithInner wi = new WithInner();InheritInner li = new InheritInner(wi);} }

構造器要傳遞一個指向外部類對象的引用,此外,還必須顯式地調用基類構造器。

內部類可以被覆蓋嗎?答案是不能。如果創建一個內部類,然后繼承其外部類并重新定義此內部類,并不會覆蓋該內部類。兩個內部類是完全獨立的,各自在自己的命名空間。


內部類標識符

每個類編譯后都會產生一個 .class 文件,內部類也會生成一個 .class 文件,但其命名有嚴格的規則:外部類的名字 + $ + 內部類的名字,例如 OuterClass.java 生成的 .class 文件包括:

OuterClass.class OuterClass$InnerClass.class

如果內部類是匿名的,編譯器會簡單地生成一個數字作為其標識符。如果內部類嵌套在別的內部類之中,只需直接將它們的名字在外部類標識符與 $ 的后面。


總結

以上是生活随笔為你收集整理的Java 内部类详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。