直切主題,把最核心的給你,超詳細深入淺出Java內部類

什麼是內部類:

一個類內部除了有屬性和方法,還可以有其他類,內部類也可以在方法或程式碼塊中。 (往下會程式碼示例)

可以簡單的理解為花括號裡 { } 裡面再定義一個類,那麼這個類就稱為:內部類。 因為理論上內部類可以在類任意位置,所以程式碼塊也好,普通方法也可以。

內部類的作用:

1.增強封裝,把內部類放在外部類當中,不允許其它類訪問這個內部類。

2.增加了程式碼一個維護性,不涉及到其他類。

3.內部類可以直接訪問外部類當中的成員。

內部類分為四種:

  • 例項內部類:直接定義在類當中的一個類,在類前面沒有任何一個修飾符。
  • 靜態內部類:在內部類前面加上一個static。
  • 區域性內部類:定義在方法當中的內部類。
  • 匿名內部類:屬於區域性的一種特殊情況。

例項內部類

//外部類
//外部類
class Outer {
String str = "一顆剽悍的種子";
//內部類
class Inner{
void fun() {
System.out.println(str);
}
}
}
public class Test2{
public static void main(String[] args) {
Outer out = new Outer();
//例項內部類
out.new Inner().fun();
}
}

執行結果:

上面程式碼示例有個細節:就是我們提到過的內部類的作用, 內部類可以訪問外部類的成員。

例項化內部類的格式:

new 外部類().new 內部類 ();

程式碼本身很簡單,只要理解類的語法和物件例項化方式就可以了,瞭解它的底層才有趣,建立內部類的時候發生了什麼? 在建立內部類的時候,會有一個外部類的引用。

我們可以用程式碼編譯後的class檔案透過我們的反編譯工具來看。

class Outer$Inner
{
final Outer this$0;
void fun()
{
System.out.println(str);
}
Outer$Inner()
{
this$0 = Outer.this;
super();
}
}

從上面的程式碼可以看到,內部類當中除了有自己的引用,還有外部類的引用。在堆中相當於外部類有一個地址,內部類有兩個地址,一個是自己內部類的,一個是指向外部類的地址。

靜態內部類

有接觸過Java 靜態這個知識點的小夥伴應該都知道,談到靜態無非就是對static關鍵字的理解和運用,這麼說你可能會好懂一些。

說得更直接點就是內部類前面加上一個 static 就是靜態內部類。

//外部類
class Outer {
static String str = "一顆剽悍的種子";
//靜態內部類
static class Inner{
void fun() {
System.out.println(str);
}
}
}
public class Test2{
public static void main(String[] args) {
new Outer.Inner().fun();;
}
}

執行結果

注意點:可以看到上面成員也是用static宣告靜態,是因為宣告static無法直接呼叫非static變數或方法。

為什麼?

我們都知道static是最先執行,在載入位元組碼就會自動呼叫,而且在主方法main之前,比構造方法早,此時非static屬性和方法還沒有完成初始化呢。

還有與上面非 static 定義內部類有兩點不同:

1.靜態內部類的建立格式不需要例項化,具體格式如下:

new 外部類(). 內部類 ();

2.靜態內部類當中沒有外部類的引用。

為什麼?

因為加上static 靜態內部類是屬於外部類的,上面所說也可以看出它沒有用new 而是透過 .類的方式。

還是透過我們的反編譯檢視class檔案,有碼有真相。

static class Outer$Inner
{
void fun()
{
System.out.println(Outer.str);
}
Outer$Inner()
{
}
}

區域性內部類

開頭說什麼是內部類當中,有說到內部類不僅可以定義在外部類當中,也可以定義在方法當中,而定義在方法當中的類稱為區域性內部類

//外部類
class Outer {
void fun_1() {
String name = "一顆剽悍的種子";
class Inner{
void fun_2() {
System.out.print(name);
}
}
Inner in = new Inner();
in.fun_2();
}
}
public class Test2{
public static void main(String[] args) {
new Outer().fun_1();
}
}

執行結果

區域性內部類有什麼侷限性呢?

1.區域性內部類只能在定義方法中使用。 可以看到程式碼示例,在方法中建立內部類並且呼叫內部類裡的方法,後續例項化只要呼叫外部類裡的 fun_1 方法就可以。

2.不能使用 public、protected、private 修飾 。 這一條是對應第一條的,你想想,你已經在方法中建立了,只在方法中使用,你還用這些許可權幹嘛 ???

3.區域性類當中不能使用static變數。 上面靜態內部類時說過,static是屬於外部類的,所以在方法裡的內部類定義static變數會報錯。

除了區域性內部類的侷限性,還可以看到在程式碼例項中,內部類是可以直接使用方法中的變數的。

(在jdk1.7之前內部類想訪問方法中的變數是需要加上final的,我們知道final是用來宣告常量的,fianl需要設定好值而且不能修改。)

jdk1.8版本之後不需要,正好我的jdk1.8 所以就不用加final了,但是真實情況下,透過反編譯工具看class檔案會發現編譯時已經幫我們自動加上了。

(你會發現隨著語言的發展,讓你更易於開發的同時,你離本質也更加的遙遠)

class Outer$1Inner
{
final Outer this$0;
private final String val$name;
void fun_2()
{
System.out.print(val$name);
}
Outer$1Inner()
{
this$0 = final_outer;
val$name = String.this;
super();
}
}

到這裡可能有小夥伴會問,為啥內部宣告變數需要加上final,這裡就不展開了,因為涉及到 final 在方法區以及程式碼執行後的堆疊關係,下次有機會再寫一篇。

匿名內部類

根據字面意思就知道沒有命名的內部類,那麼匿名內部類就是沒有構造器的,因為我們都知道類的構造器需要跟類同樣的命名。

new 父類 或 介面

上面圍繞四種內部類展開,例項內部類,靜態內部類、區域性內部類、匿名內部類,因為匿名內部類的應用是比較少,所以簡單的談談就沒有程式碼示例,等有用到,而且好的例子,可以再單獨寫一篇滴。

版權宣告:本文源自 網路, 於,由 楠木軒 整理釋出,共 2911 字。

轉載請註明: 直切主題,把最核心的給你,超詳細深入淺出Java內部類 - 楠木軒