Static Nested Class 和 Inner Class的不同

Java Nested Class

Java Nested Class 對不少人來說是個讓人迷惑的東西, 也是面試中容易考倒人的概念, 筆者最近稍微深入研究了一下這個題目,現將一點心得體會跟大家分享, 希望能對其他人有所幫助, 講錯的地方也歡迎大家指正.


首先先澄清一個相對比較簡單的讓人模糊概念.

1. Static Nested Class 不是 Inner Class.
Jave Nested Class 分爲兩大類:1. Static Nested Class;2. Non-static Nested Class.

Non-Static Nested Class 纔是真正的Inner Class. 正統的書上是這麼區分的, 至於有沒有道理, 是個仁者見仁, 智者見智的問題.

在筆者看來, 我覺得如此分沒有什麼意義, 甚至覺得將 Non-Static Nested Class 歸入 Inner Class更合理一些, 因爲, Inner Class 跟 其他 class member 和 class method 一樣, 都是 outerclass 的一個成員.

但權威們要這麼區分, 我等也只能跟風了.

2. Inner Class 的 Scope 問題.
A. 如果 outer class 的 scope 是 public, 那麼四個不同的 scope 對 Inner Class 都有不同的意義.
public -- 任何一個其他class 都能看到和使用.

private -- Scope只限於包含這個Inner Class 的 Outer Class 中, 也就說只有 Outer Class 的成員能夠看到和使用, 在這個Outer Class 外面看不到這個Inner Class.

package -- 這個是默認行爲(default), 只有同一個package 的 才能看到和使用這個 Inner Class.

protected -- 比package稍微多一點, 不同package, 但繼承了Outer Class 的 子 類 ( extended class of Outer Class), 也能使用這個 Inner Class.

B. 我們知道主類(CLASS) 的 scope 只能是 public 或者 package, private 和protected 對 主類(CLASS)沒有意義. 主CLASS就是供其他CLASS 使用的, 要不給所有的CLASS 用, 要不給同一個 package 的CLASS 用. 其他兩個scope沒有任何意義, JAVA compiler 禁止主類(Main Class)使用 private和protected.

好,有意思的地方來了, 如果 主類的scope 是 package, 那麼作爲成員的Inner Class的 scope 該如何定義?
因爲主類(Outer Class) 的 scope 是 package, 那麼 , 只有同一個package的CLASS可以看到這個Outer Class.

既然如此, 對Inner Class 而言, 只有private 和 默認(defalut package) 有意義.

至於其他的protected, public和package, 對 Inner Class來說, 含義是一樣的, 都是 只有 同一個package的其他CLASS 可以 看到和使用這個Inner Class.

在這種情況下, public 和 protected 純屬扯蛋, 除了把人腦子搞亂外,沒有任何意義.

我不瞭解的是, 爲什麼compiler不象針對Main Class一樣, 對scope爲package(默認)的CLASS 的 Inner Class 使用相似的限制, 只允許有private和package(默認), 這樣可以避免混亂.

private scope的意思沒有變, 還是隻有同一個OUT CLASS的其他成員纔可以看到和使用這個 Inner Class, private only to this "Outer Class".

3. Static-Nested Class
多數情況下, 使用比較多的都是這類CLASS, 因爲比較簡單, 方便. 學過一些JAVA的人知道, 使用Nested Class
的主要目的有兩個:1. 將邏輯上緊密相關的CLASS放在一起(在同一個主CLASS中); 2. 只被一個主CLASS使用的非常侷限性輔佐功能, 換句話說, 相當於你要寫個HELPER CLASS, 但又只被一個主CLASS使用.

這麼做,可以讓你的程序更加緊湊, 容易閱讀, 也安全.

談到安全問題, 一般情況下, 我都喜歡將 Static-Nested Class 的scope設計成private. 這樣, 外面的CLASS根本看不到我的implementation, 這樣我就Hide了我的Logic, 這個叫encapsulation ,是面象程序一個很重要的概念.

如果你是個熟手, 甚至可以更進一步, 將你的Nested Class up-casting成 interface(接口), 人家更不知道你裏面是什麼東西了.

4. Static-Nested Class 的成員, 既可以定義爲靜態的(static), 也可以定義爲動態的(instance).
Nested Class的靜態成員(Method)只能對Outer Class的靜態成員(static memebr)進行操作(ACCESS), 而不能Access Outer Class的動態成員(instance member).

而 Nested Class的動態成員(instance method) 卻可以 Access Outer Class的所有成員, 這個概念很重要, 許多人對這個概念模糊.

有一個普通的原則, 因爲靜態方法(static method) 總是跟 CLASS 相關聯(bind CLASS), 而 動態方法( (instance method) 總是跟 instance object 相關聯, 所以,

靜態方法(static method)永遠不可以Access跟 object 相關的動態成員(instance member),
反過來就可以, 一個CLASS的 instance object 可以 Access 這個 Class 的任何成員, 包括靜態成員(static member).

5. 跟其他普通CLASS成員的區別.

雖然 nested class 跟其他CLASS成員在絕大多數情況下一樣, 地位和功能上沒有什麼不同.

Nested Class 是個類(Class) ,是可以初始化和賦值的(create an instance object), 請注意, Static Nested Class 和 Inner Class( Non-Static Nested Class) 在 語法上是不同的.

舉個簡單的例子.
class A
{
private int i = 6;
private static String s = "Nested Class";

int getValue()
{
return i;
}

private static class B
{
void setIntValue(int i)
{
new A().i = i;
}
int getIntValue()
{
return new A().i;
}
static void setStrValue(String s)
{
A.s = s;
}
static String getStrValue()
{
return A.s;
}
}
// Be careful , all members of C must not static!!!!!
private class C
{
void setIntValue(int i)
{
new A().i = i;
}
int getIntValue()
{
return new A().i;
}
}

public static void main(String[] args)
{
System.out.println("String value:" + B.getStrValue()); // OK, class access static method
System.out.println("String value:" + new B().getStrValue()); // OK, object access it's static method
System.out.println("Int value:" + new B().getIntValue()); // OK, object access instance method
// System.out.println("Int value:" + B.getIntValue()); // Not OK. class can not access instance method.

// creat an instance object from outside.
A.B myClass = new A.B(); // ok. because B is static member of A.
// If nested class is not static, you have to do this to create an object.
A.C myClass2 = new A().new C(); // OK. create instance of C from an instance of A.
//A.C myClass3 = new A.C(); // ERROR. can not access a instance member from Class.
}
}

請注意CLASS B 和 CLASS C 的區別, 其中B就是常見的Static Nested Class, 而C就是最常見的Inner Class. 定義C 跟 定義 B 是不一樣的. 關鍵要理解
靜態的成員只跟CLASS掛鉤, 而動態成員必須跟object掛鉤.

其中 Inner Class又可分爲兩類或者三類.

1. 普通的 Inner Class, 在 Outer Class 中定義, 跟 其他成員一樣.

2. Local Inner Class. 在 Outer Class 的方法中或者任何一個block{}中定義,
方法中定義的Inner Class, 其 input parameter 必須是 Final 修飾過的變量.

3. 匿名 Inner Class(Anonymous Inner Class). 簡單的說就是沒有名字.

2 和 3 區別不到, 只有 Syntax上的區別.
Local Inner Class, 顧名思義, 它的SCOPE, 只在 定義它的 那個 block 中, 也就是在
包圍它的 {} 中.

其他的使用,跟 普通的 Inner Class 差不多, 就不多說了.

舉個簡單的例子.

public class AbstracDemo
{
private abstract class MyAbs
{
abstract void print();
int readline()
{
return i;
}
}/*
private class MyAbsDemo extends MyAbs
{
void print()
{
System.out.println("----------:"+readline());
}
int readline()
{
return i;
}
}
*/
public int i = 12;

public static void main(String[] args)
{
AbstracDemo d = new AbstracDemo();
System.out.println("******:"+d.i);
class MyAbsDemo extends MyAbs
{
MyAbsDemo()
{
new AbstracDemo().super();
}
void print()
{
System.out.println("----------:"+readline());
}
int readline()
{
return new AbstracDemo().i;
}
}
MyAbsDemo m = new MyAbsDemo();
System.out.println("******:"+m.readline());
m.print();

}
}

Main當中的MyAbsDemo, 就是個典型的Local Inner Class.

發佈了53 篇原創文章 · 獲贊 32 · 訪問量 83萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章