十二、類的高階特性
1、Java類包
一個完整的類名需要包名與類名的組合,任何一個類都隸屬於一個類包,只要保證同一類包中的類不同名,就可以有效地避免同名類衝突的情況。
使用import關鍵字匯入包。
2、final變數
final關鍵字可用於變數宣告,一旦該變數被設定,就不可以再改變該變數的值。
通常,由final定義的變數為常量。例如,在類中定義PI值,可以使用如下語句:final double PI=3.14;
3、final方法
定義為final的方法不能被重寫。
將方法定義為final型別可以防止任何子類修改該類的定義與實現方式,同時定義為final的方法執行效率要高於非final方法。
如果一個父類的某個方法被設定為private修飾符,子類將無法訪問該方法,自然無法覆蓋該方法,
4、final類
定義為final的類不能被繼承。
如果希望一個類不允許任何類繼承,並且不允許其他人對這個類有任何改動,可以將這個類設定為final形式。
final類的語法如下:final 類名{}
如果將某個類設定為final形式,則類中的所有方法都被隱式設定為final形式,但是final類中的成員變數可以被定義為final或非final形式。
5、內部類
5.1 成員內部類
最常見的內部類就是成員內部類,也稱作普通內部類;
public class Outer {
private int a = 1;
private String name = "張勝男";
//成員內部類
public class Inner{
int b = 2;
String name = "李偉";
public void test(){
System.out.println("a:"+a);
System.out.println("b:"+b);
System.out.println("外部類的名字:"+Outer.this.name);
System.out.println( "內部類的名字:"+name);
}
}
public static void main(String[] args) {
Outer outer = new Outer();//建立外部類
Inner inner = outer.new Inner();//通過外部類建立內部類
inner.test();//呼叫內部類方法
}
}
1)Inner類定義在Outer類的內部,相當於Outer類的成員變數的位置,Inner類可以使用任意訪問修飾符,如:public、private、protected等。
2)Inner類中定義的test()方法可以訪問Outer類中的資料,不受訪問控制符的影響。
3)定義了成員內部類後,必須使用外部類物件來建立內部類物件,而不能直接去 new 一個內部類物件,即:內部類 物件名 = 外部類物件.new 內部類( );如建立Inner的內部類物件:要先建立外部類物件:Outer o = new outer(); 建立內部類:Inner i = o.new Inner();訪問Inner中的test()方法:i.test();
4)如果外部類和內部類具有相同的成員變數或方法,內部類可以直接訪問內部類的成員變數或方法,但如果內部類訪問外部類的成員變數或者方法時,需要使用this關鍵字;
5.2 區域性內部類
定義在方法中的內部類,方法內部類只在該方法內可以用。
public class Outer {
private int a = 1;
private String name = "張勝男";
public void show(){
int b = 22;
//區域性內部類(方法內部類)
class Inner{
int c = 2;
String name = "李偉";
public void test(){
System.out.println("a:"+a);
System.out.println("外部類的名字:"+Outer.this.name);
//這裡b並沒有用final修飾(1.8之後java隱式的將b修飾為final)如果你新增一個x=8,這裡就會報錯。
System.out.println("外部類方法的屬性b:"+b);
System.out.println("內部類的名字:"+name);
}
}
Inner inner = new Inner();
inner.test();
}
public static void main(String[] args) {
Outer outer = new Outer();//建立外部類
outer.show();
}
}
注意:
1)由於方法內部類不能在外部類的方法以外的地方使用,內部類不能被public、private、static修飾;
2)在外部類中不能建立區域性內部類的例項;
3)建立區域性內部類的例項只能在包含他的方法中;
4)區域性內部類訪問包含他的方法中的變數必須有final修飾;
5)外部類不能訪問區域性內部類,只能在方法體中訪問區域性內部類,且訪問必須在內部類定義之後。
為什麼區域性內部類呼叫外部類方法的屬性要用final修飾?
主要原因還是生命週期:當方法return後,方法中的區域性變數就會隨之銷燬,但是我的內部類物件可能仍然還存在的(當不在被使用才會被垃圾回收器回收)這時在內部類中訪問了區域性變數x,但此時的x已經被銷燬,內部類訪問了一個並不會存在的變數,這就形成了一個矛盾。
根本原因就是:內部類的生命週期比區域性變數的長。
5.3 匿名內部類
匿名內部類可以使你的程式碼更加簡潔,你可以在定義一個類的同時對其進行例項化。它與區域性類很相似,不同的是它沒有類名,如果某個區域性類你只需要用一次,那麼你就可以使用匿名內部類.
特點:
* 可以把匿名內部類看成是一個沒有名字的區域性內部類。
* 定義在方法當中。
* 必須在定義匿名內部類的時候建立他的物件。
//A:作用:匿名內部類是建立某個型別子類物件的快捷方式。
//B:格式:
new 父類或介面(){
//進行方法重寫
//如果是建立了繼承這個類的子類物件,我們可以重寫父類的方法
//如果是建立了實現這個介面的子類物件,我們必須要實現該介面的所有方法
};
//已經存在的父類:
public abstract class Person{
public abstract void eat();
}
//定義並建立該父類的子類物件,並用多型的方式賦值給父類引用變數
Person p = new Person(){
public void eat() {
System.out.println(“我吃了”);
}
};
//呼叫eat方法
p.eat();
//使用匿名物件的方式,將定義子類與建立子類物件兩個步驟由一個格式一次完成,。雖然是兩個步驟,但是兩個步驟是連在一起完成的。
//匿名內部類如果不定義變數引用,則也是匿名物件。程式碼如下:
new Person(){
public void eat() {
System.out.println(“我吃了”);
}
}.eat();
匿名內部類注意事項:
* 匿名內部類不能有構造方法;
* 匿名內部類不能定義任何靜態成員、方法和類
* 匿名內部類不能有public、protected、private、static
* 只能建立匿名內部類的一個例項
* 一個匿名內部類一定是在new的後面,用其隱含實現一個介面或實現一個類
* 匿名內部類為區域性內部類,所以區域性內部類的所有限制都對其生效
* 在匿名內部類中使用this時,這個this指的是匿名類本身。如果要使用外部類的方法和變數的話,應該加上外部類的類名。
5.4 靜態內部類
一個靜態內部類中可以宣告static成員,但是在非靜態內部類中不可以宣告靜態成員。靜
態內部類有一個最大的特點,就是不可以使用外部類的非靜態成員,所以靜態內部類在程式開發中比較少見。
public class Outer {
private int a = 1;
private static String name = "張勝男";
//成員內部類
public static class Inner{
int b = 2;
String name = "李偉";
public void test(){
System.out.println("a:"+new Outer().a);
System.out.println("外部類的名字:"+Outer.name);
System.out.println("內部類的名字:"+name);
}
}
public static void main(String[] args) {
Inner inner = new Inner();//直接建立靜態內部類
inner.test();//呼叫靜態內部類方法
}
}
1)靜態內部類不能直接訪問外部類的非靜態成員,但,可以通過new 外部類().成員的方式訪問;
2)如果外部類的靜態成員與內部類的靜態成員相同, 可以通過"類名.靜態成員"來訪問外部類的靜態成員;如果不同,可以直接呼叫外部類的靜態成員名。
3)建立靜態內部類的物件時,不需要外部類的物件,可以直接建立;
5.5 內部類的繼承
內部類和其他普通類一樣,同樣可以被繼承,這樣給本來就十分靈活的內部類增加了更好的結構性和程式碼複用性。
只是內部類的繼承和普通類有一些不同之處,是在使用時需要多加註意的。因為內部類在建立時需要外部類的引用,所以在內部類的繼承上也需要外部類的協助。
class WithInner{
class Inner{
}
}
public class test3 extends WithInner.Inner{
test3(WithInner wi){
wi.super();
}
public static void main(String[] args){
WithInner wi = new WithInner();
test3 t3 = new test3(wi);
}
}
首先在繼承語句extends處,注意名稱空間,需要加上外圍類名,才能對應上正確的內部類。
其次是構造物件上,這裡需要自己寫一個接受外圍類引用的構造器,來給匯出類提供建立物件的基本環境。
注意在構造器中的這一句wi.super()這是必須在構造器中使用的,才能夠成功的構造出一個繼承自內部類的物件。