java內部類之成員內部類、靜態內部類
如同一個人是由大腦、肢體、器官等身體結果組成,而內部類相當於其中的某個器官之一,例如心臟:它也有自己的屬性和行為(血液、跳動)顯然,此處不能單方面用屬性或者方法表示一個心臟,而需要一個類,而心臟又在人體當中,正如同是內部類在外部內當中
廣泛意義上的內部類一般來說包括這四種:成員內部類、區域性內部類、匿名內部類和靜態內部類。下面就先來了解一下這四種內部類的用法。
一、成員內部類:成員內部類是最普通的內部類,它的定義為位於另一個類的內部,成員內部類可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態成員)。執行結果:12//外部類 class Out { private int age = 12; //內部類 class In { public void print() { System.out.println(age); } } } public class Demo { public static void main(String[] args) { Out.In in = new Out().new In(); in.print(); //或者採用下種方式訪問 /* Out out = new Out(); Out.In in = out.new In(); in.print(); */ } }
從上面的例子不難看出,內部類其實嚴重破壞了良好的程式碼結構,但為什麼還要使用內部類呢?
因為內部類可以隨意使用外部類的成員變數(包括私有)而不用生成外部類的物件,這也是內部類的唯一優點
如同心臟可以直接訪問身體的血液,而不是通過醫生來抽血
程式編譯過後會產生兩個.class檔案,分別是Out.class和Out$In.class
其中$代表了上面程式中Out.In中的那個 .
Out.In in = new Out().new In()可以用來生成內部類的物件,這種方法存在兩個小知識點需要注意
1.開頭的Out是為了標明需要生成的內部類物件在哪個外部類當中
2.必須先有外部類的物件才能生成內部類的物件,因為內部類的作用就是為了訪問外部類中的成員變數
內部類中的變數訪問形式:
執行結果:class Out { private int age = 12; class In { private int age = 13; public void print() { int age = 14; System.out.println("區域性變數:" + age); System.out.println("內部類變數:" + this.age); System.out.println("外部類變數:" + Out.this.age); } } } public class Demo { public static void main(String[] args) { Out.In in = new Out().new In(); in.print(); } }
區域性變數:14
內部類變數:13
外部類變數:12
注意:
1、成員內部類可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態成員)。
2、當成員內部類擁有和外部類同名的成員變數或者方法時,會發生隱藏現象,即預設情況下訪問的是成員內部類的成員。如果要訪問外部類的同名成員,需要以下面的形式進行訪問:
外部類.this.成員變數
外部類.this.成員方法
3、雖然成員內部類可以無條件地訪問外部類的成員,而外部類想訪問成員內部類的成員卻不是這麼隨心所欲了。在外部類中如果要訪問成員內部類的成員,必須先建立一個成員內部類的物件,再通過指向這個物件的引用來訪問4、成員內部類是依附外部類而存在的,也就是說,如果要建立成員內部類的物件,前提是必須存在一個外部類的物件。
5、內部類可以擁有private訪問許可權、protected訪問許可權、public訪問許可權及包訪問許可權。如果成員內部類Inner用private修飾,則只能在外部類的內部訪問,如果用public修飾,則任何地方都能訪問;如果用protected修飾,則只能在同一個包下或者繼承外部類的情況下訪問;如果是預設訪問許可權,則只能在同一個包下訪問。這一點和外部類有一點不一樣,外部類只能被public和包訪問兩種許可權修飾。由於成員內部類看起來像是外部類的一個成員,所以可以像類的成員一樣擁有多種許可權修飾。
二、靜態內部類:靜態內部類也是定義在另一個類裡面的類,只不過在類的前面多了一個關鍵字static。靜態內部類是不需要依賴於外部類的,這點和類的靜態成員屬性有點類似,並且它不能使用外部類的非static成員變數或者方法,這點很好理解,因為在沒有外部類的物件的情況下,可以建立靜態內部類的物件,如果允許訪問外部類的非static成員就會產生矛盾,因為外部類的非static成員必須依附於具體的物件。
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}
靜態類的使用場景:(1) 外部類需要使用內部類,而內部類無需使用外部類的資源
(2) 內部類可以獨立外部類建立物件
使用靜態內部類的好處是加強了程式碼的封裝性以及提高了程式碼的可讀性,舉個例子:
public class Person{
//姓名
private String name;
//家庭
private Home home;
//建構函式設定屬性值
public Person(String _name){
name = _name;
}
/* home、name的getter/setter方法省略 */
public static class Home{
//家庭地址
private String address;
//家庭電話
private String tel;
public Home(String _address,String _tel){
address = _address;
tel = _tel;
}
/* address、tel的getter/setter方法省略 */
}
}
把Home放在Person內部,一看便知道Home是Person的一個屬性。使用的時候也很方便,如下程式碼:public static void main(String[] args) {
Home home = new Person.Home("上海", "021");
Person p1 = new Person("張三");
Person p2 = new Person("李四");
p1.setHome(home);
p2.setHome(home);
}
這裡建立一個home物件,p1和p2都使用這個home物件,p1和p2共享同一個home物件。如果把Home換成普通內部類,情況就不同了,這時程式碼變成:
public static void main(String[] args) {
Person p1 = new Person("張三");
Home home = p1.new Home("上海", "021");
p1.setHome(home);
Person p2 = new Person("李四");
p2.setHome(home);
}
這裡p1和p2依然共享同一個home物件,但此時home物件和p1是同生共死的,如果p1物件消亡,那麼p2就沒有
家了,這對p2來說實在不公平,而如果為p1和p2都建立一個Home物件,又浪費資源。所以在這個例子中,
使用靜態內部類比普通內部類要合適。
靜態內部類和普通內部類的區別
(1)普通內部類不能宣告static的方法和變數
普通內部類不能宣告static的方法和變數,注意這裡說的是變數,常量(也就是final static修飾的屬性)
還是可以的,而靜態內部類形似外部類,沒有任何限制。
(2)使用靜態內部類,多個外部類的物件可以共享同一個內部類的物件。
使用普通內部類,每個外部類的物件都有自己的內部類物件,外部物件之間不能共享內部類的物件