一直打算讓自己的Java回爐重新鍛造一下,那么,從現在開始吧。
本文是閱讀《Thinking in Java》(以下簡稱TIJ)第七章之后的產物,會包含以下:
- 一個問題
- 一些思考
- 重載與重寫
- final
一個問題
如圖代碼,test明明是類A的私有成員變量,(1)為什么其子類B的實例能夠正常使用set方法打印出test?(2)這又使我想起了前一段時間一個朋友問我的問題,new一個子類的時候,是不是會同時new出對應的父類?構造方法到底僅僅只是初始化成員變量,還是同時會申請內存空間?
- 為什么子類B的實例能夠正常使用set方法打印出test?
- new一個子類的時候,是不是會同時new出對應的父類?
首先我們需要明確的繼承的一些特性,** 子類擁有父類的所有屬性和方法 ,這是一點。第二點, private修飾的變量、方法僅類內可訪問 **,出了這個類,對不起你看不到。當然了,通過反射之類的技巧還是有辦法的,但是這不在我的討論范圍之內。
TIJ對第一點有一些印證的描述:
子類對象的正確初始化至關重要,而且也僅有一種方法來保證這一點,在構造器中調用父類構造器來執行初始化,父類構造器具有執行父類初始化所需要的所有東西。
那么以上的問題應該可以迎刃而解了:private修飾的test僅在A類中是可以訪問到的,雖然B類繼承了A類,擁有這一屬性,但是遺憾的是他并沒有打開箱子的密碼,并不能訪問到。但是public修飾的set方法子類B是可以訪問的,于是調用set方法打印了test的值。在new一個子類的時候并不會同時new出對應的父類,而是會調用父類的構造器。構造方法可以理解成一段比較特殊的代碼,可以用來初始化實例的數據,但是只有在new 構造方法名 的時候才會申請內存空間。
一些思考(1)
即使在子類中調用父類的構造器,有時也無法保證所有成員都被初始化。事實上在我們平時寫代碼的時候,有很多成員并非是在構造器中初始化的,而是在我們需要用之前初始化,所以當我們在考慮到繼承的情況下,需要多考慮一些未在構造器中被初始化的成員。
重載與重寫
-
重載
重載是指方法名都一樣,但是參數不一樣,返回值也可以一樣。但是如果參數完全相同,只有返回值是不一樣的,那是不可行的。
2.png 重寫
重寫通常發生在子類,子類寫一個父類中有的同名方法(方法參數,返回類型一致),那么在調用這個名字的方法時將會調用子類中的這個方法。當你確定要覆蓋父類的方法時,建議使用注解@Override,這樣可以防止你在不想重載時而以外地進行了重載。
一些思考(2)
看到Override這一塊的時候,不經想起來了Android中的Handler,平時我們的寫法都是
private static Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
關于以上寫static修飾符將會在下文給出解釋。
首先Handler是個抽象類,但是我點進去,搜了一下abstract這個關鍵字,沒有!一個都沒有!
關于abstract class 文檔是這樣描述的:抽象類是不完全的類,或者被認為是不完全的。那么這個就容易理解了,抽象類并未強制要求你一定要有abstract method,只要你自己認為這個類是abstract class就可以給他加上。那么"="右邊的寫法是怎么回事呢?
右邊的寫法想要表達的意思是:創建一個繼承自Handler的匿名類對象。可能你會和我有一樣的疑惑,名字不是handler在左邊掛著呢么?如果你有這個疑惑……恭喜,你該和我一起回去重造Java了……因為上面說的很清楚了是"="右邊的,右邊通過new表達式返回的引用被自動轉型為Handler,所以說這是一個Handler的子類,用一個通俗易懂的問結束這個話題:那么這個子類的名呢?
final
final關鍵字根據上下文和修飾對象的不同可能會有一些差別。
變量
如果final修飾的是基本數據類型,那么此變量恒定不變。如果final修飾的是引用類型,那么一旦該引用類型被初始化指向一個對象,那么久無法將他改為指向另一個對象。但是需要注意的是對象本身的值是可以改變的。方法
final修飾的方法不可以被復寫。類
final修飾的方法不可以被繼承。
為什么匿名內部類中形參要是final的?
在寫Android程序時,很多時候都會碰到需要向匿名內部類傳參的情況。一般這種情況我們也就是改一下……那么為什么要傳入final類型呢?
在內部類中的屬性和外部方法的參數兩者從外表上看是同一個東西,但實際上卻不是,所以他們兩者是可以任意變化的,也就是說在內部類中我對屬性的改變并不會影響到外部的形參,然而這從程序員的角度來看這是不可行的,畢竟站在程序的角度來看這兩個根本就是同一個,如果內部類該變了,而外部方法的形參卻沒有改變這是難以理解和不可接受的,所以為了保持參數的一致性,就規定使用 final 來避免形參的不改變。
** 簡單理解就是,拷貝引用,為了避免引用值發生改變,例如被外部類的方法修改等,而導致內部類得到的值不一致,于是用 final 來讓該引用不可改變。 **
** 故如果定義了一個匿名內部類,并且希望它使用一個其外部定義的參數,那么編譯器會要求該參數引用是 final 的。 **
最后揭曉一下以上為什么要用static修飾Handler,因為內部類會隱性的持有一個外部類的引用,這個外部類可能是個Activity,因為這可能會導致Activity無法被回收,從而導致內存泄漏。