[TOC]
面向對象(OOP)的程序是由對象組成的,每個對象包含對用戶公開的特定功能部分和隱藏的實現部分。
# 類
## 面向對象三大特性
封裝、繼承、多態
* 封裝隱藏了類的內部實現機制,可以在不影響使用的情況下改變類的內部結構,同時也保護了數據
* 繼承可以重用父類代碼,實現代碼復用和可擴展的效果
* 多態指對象的一個方法在調用時可以有多種狀態,即父類引用可以持有子類對象
* 多態實現的兩種形式:基于繼承重寫、基于接口
* 多態存在的三個條件:繼承、重寫、父類引用持有子類對象
* 非靜態成員方法的調用:編譯看父類,運行看子類
* 多態優點:不用創建一堆子類對象的引用;多態缺點:不能使用子類特有的成員屬性和成員方法
***注意點***
1、實現封裝的關鍵在于,絕對不能讓類中的方法直接地訪問其他類的實例域(對象中的數據),程序僅通過對象的方法與對象數據進行交互。
2、對象狀態的改變必須通過調用方法實現。
## 類之間的關系
依賴、聚合、繼承
* 依賴是最明顯、最常見的關系,如果一個類的方法操縱另一個類的對象,就說一個類依賴于另一個類
* 聚合指類A的對象包含類B的對象
## 自定義類
1、在一個Java源文件中,只能有一個公有類,但可以有任意數目的非公有類。
2、顯式參數指方法名后面括號中的數值,隱式參數指出現在方法名前的對象(在方法內部可通過this來表示隱式參數)。
3、靜態方法是一種不能向對象實施操作的方法,也就是沒有隱式參數,不能操作對象,但可以訪問自身類中的靜態域。
4、按值調用表示方法接收的是調用者提供的值,按引用調用表示方法接收的是調用者提供的變量地址。
5、類設計技巧:
* 一定要保證數據私有
* 一定要對數據初始化,可以提供默認值,也可以在構造器中設置默認值
* 不要在類中使用過多的基本類型
* 不是所有的域都需要獨立的域訪問器和域更改器
* 將職責過多的類進行分解
* 類名和方法名要能夠體現它們的職責
***重點***
* Java總是采用按值調用,方法得到的是參數值的一個拷貝,不能修改傳遞給它的任何參數變量的內容
## 內部類
將一個類的定義放在另一個類的定義內部,這就是內部類
內部類分為成員內部類、靜態內部類、局部內部類和匿名內部類
### 成員內部類
相當于外部類的一個成員。
```java
public class OuterClass {
private String mString = "a";
private void outerMethod() {
// 使用內部類屬性或方法需要提供內部類實例來實現
InnerClass innerClass = new InnerClass();
innerClass.innerMethod();
}
public class InnerClass {
// private static String mStaticString; ERROR!
public void innerMethod() {
// 使用外部類屬性
mString = "b";
// 使用外部類方法方法
outerMethod();
}
}
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.getInnerClass();
innerClass.innerMethod();
}
}
```
1、訪問規則
* 內部類可以訪問外部類的所有屬性和方法,即使是私有的
* 外部類要訪問成員內部類的屬性和方法,則需要通過成員內部類的實例來實現
2、注意事項
* 成員內部類中不能有任何 static 的屬性和方法
* 成員內部類是依附于外部類的,只有先創建了外部類對象,才能夠創建成員內部類,推薦使用 getxxx() 來獲取成員內部類
* 成員內部類中持有一個外部類的引用
### 靜態內部類
靜態內部類是一個碰巧被聲明在外部類中的普通類。
```java
public class OuterClass {
private static String sString;
private void outerMethod() {
// 外部類可訪問私有靜態類的屬性和方法
InnerClass innerClass = new InnerClass();
innerClass.innerMethod();
}
private static class InnerClass {
private void innerMethod() {
// 靜態內部類只可以訪問外部類的靜態成員
sString = "a";
}
}
public static void main(String[] args) {
// 創建靜態內部類對象不需要外部類對象
InnerClass innerClass = new InnerClass();
innerClass.innerMethod();
}
}
```
* 靜態內部類不持有外部類的引用
* 和其他靜態成員一樣,被聲明為 private 時,只有外部類可訪問
* 靜態內部類不能直接訪問外部類的任何非 static 成員變量和方法;卻可以直接訪問外部類的靜態成員,包括私有的
* 創建靜態內部類時不需要創建外部類對象
* 聲明在接口中的內部類自動成為 public 和 static
### 局部內部類
```java
void setData() {
class ClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
// do click
}
}
mView.setOnClickListener(new ClickListener());
}
```
局部內部類嵌套在方法和作用域內,像是方法里的一個局部變量一樣
* 局部內部類對外界完全隱藏,即使是外部類也不能訪問它
* 局部內部類可以訪問所在作用域的局部變量,但必須聲明為 final
* 有時候 final 的限制會不方便,可以使用一個長度為 1 的數組類替代
### 匿名內部類
```java
void setData() {
mView.setOnClickListener(new View.OnClickListener() {
// do click
});
}
```
對局部內部類的一種深化,只需要創建局部內部類的一個對象時,就不需要命名了
1、定義
* 匿名內部類語法格式為 `new SuperType(construction parameters){}`
* 父類后面括號中的參數會傳遞給父類的構造器
* 匿名內部類終歸還是個類。如果 SuperType 是一個接口,匿名類實現這個接口,并擴展自 Object 類;如果 SuperType 是一個類,則匿名類是該類的子類
2、注意
* 匿名內部類屬于局部內部類,局部內部類的限制對于它同樣生效
* 匿名內部類中不能定義構造方法,因為它連名字都么有,但可以使用初始化語塊代替構造方法
匿名內部類初始化語塊示例:
```java
invite(new ArrayList<String>(){
{
add("Harry");
add("Tony");
}
};
);
```
### final關鍵字的理解
1、final的意思是【無法改變的】、【最終的】,可以修飾非抽象類、非抽象類的成員變量和成員方法
2、final類不能被繼承,沒有子類,其中的方法默認是final的
3、final方法不能被重寫,但可以被繼承(final不能用于修飾構造方法)
4、final成員變量表示常量,只能被賦值一次,賦值后不再改變。
5、使用final聲明基礎數據類型時,數值恒定不變;使用final聲明對象引用時,引用的對象恒定不變,但對象的數據可變;使用final聲明數組類型時,引用的數組恒定不變,但數組內的數據可變。
優點:
1、編譯器遇到final方法時會轉入內嵌機制,提高效率。
2、可以安全的在多線程環境下共享,不需要額外的同步開銷。
### 為什么匿名內部類使用局部引用要用final
1、匿名內部類屬于一種局部內部類。
2、編譯后局部內部類中會有一個成員變量,是對外部局部變量的引用的拷貝,在局部內部類使用外部局部變量值時都是通過這個引用進行的。
3、為避免這個成員變量的值(引用的對象)被外部類的方法修改,導致內部類在使用時得到的值不一樣,需要使用final讓該成員變量不可變。
4、局部變量位于方法內部,在虛擬機的棧上,意味著這個變量無法進行共享,匿名內部類無法直接訪問,只能通過值傳遞的方式,傳遞給匿名內部類。
5、而類的成員變量在虛擬機的堆上,內部類可以直接獲取這個變量,故類的成員變量不需要聲明為final內部類就可訪問。
參考鏈接
[java提高篇(八)----詳解內部類](https://www.cnblogs.com/chenssy/p/3388487.html)
# 對象
1、一個類的多個方法有相同的名字、不同的參數,便產生了重載。編譯器通過用各個方法給出的參數類型與特定方法調用所使用的值類型進行匹配來挑選出相應的方法,這個過程稱為重載解析。
2、完整的描述一個方法,需要指出方法名以及參數類型,這叫做方法的簽名。返回類型不是方法簽名的一部分,因此不能有兩個名字相同、參數類型也相同卻返回類型不同的方法。
# 繼承
## 繼承的 private 成員問題
關于子類是否可以繼承父類 private 成員問題,原來大家已經討論很久了:
一種是子類不可以繼承父類的私有成員,私有成員是默認為 final 的,是不允許覆蓋的。但父類提供了 public、protected 方法訪問其私有成員時,子類或外部類可以通過 public、protected 方法訪問到。
另一種說法是子類繼承父類的所有成員,包括私有的。private,public,protected 和繼承沒有關系,他們對成員函數和變量的限制只是在成員的可見性上。因此私有成員變量和方法在子類中不可見,也就是擁有它,但不能使用它,必須通過父類的 public、protected 方法訪問。
個人比較傾向于第一種說法。可以看下參考中的[《private 繼承之爭》](http://www.ithome.com.tw/voice/90371)一文,講解的比較不錯。
參考
[private 繼承之爭](http://www.ithome.com.tw/voice/90371)
[私有的成員能被子類繼承嗎?](http://www.blogjava.net/sitinspring/archive/2007/12/04/165288.html)
[Java 中子類是否會繼承父類中的 private 成員](http://woyixiaorenne.iteye.com/blog/2312477)
## 繼承的構造方法問題
子類和父類的構造方法不存在繼承關系,而是調用關系,存在以下原則:
* 子類構造過程中必須調用父類的構造方法
* 如果子類沒有顯示調用父類構造方法,則系統默認調用父類的無參構造方法(若系統無無參構造方法,編譯報錯)
* 一個類未聲明任何構造方法時,系統會默認生成一個無參構造方法。當聲明了有參構造方法時,就不會自動生成無參構造方法了
靜態代碼塊、構造代碼塊、構造方法的執行順序:
父類靜態代碼塊→子類靜態代碼塊→父類構造代碼塊→父類構造方法→子類構造代碼塊→子類構造方法
參考文檔:
[關于 Java 內部類的小抄](http://blog.jrwang.me/2016/java-inner-class/)
- 導讀
- Java知識
- Java基本程序設計結構
- 【基礎知識】Java基礎
- 【源碼分析】Okio
- 【源碼分析】深入理解i++和++i
- 【專題分析】JVM與GC
- 【面試清單】Java基本程序設計結構
- 對象與類
- 【基礎知識】對象與類
- 【專題分析】Java類加載過程
- 【面試清單】對象與類
- 泛型
- 【基礎知識】泛型
- 【面試清單】泛型
- 集合
- 【基礎知識】集合
- 【源碼分析】SparseArray
- 【面試清單】集合
- 多線程
- 【基礎知識】多線程
- 【源碼分析】ThreadPoolExecutor源碼分析
- 【專題分析】volatile關鍵字
- 【面試清單】多線程
- Java新特性
- 【專題分析】Lambda表達式
- 【專題分析】注解
- 【面試清單】Java新特性
- Effective Java筆記
- Android知識
- Activity
- 【基礎知識】Activity
- 【專題分析】運行時權限
- 【專題分析】使用Intent打開三方應用
- 【源碼分析】Activity的工作過程
- 【面試清單】Activity
- 架構組件
- 【專題分析】MVC、MVP與MVVM
- 【專題分析】數據綁定
- 【面試清單】架構組件
- 界面
- 【專題分析】自定義View
- 【專題分析】ImageView的ScaleType屬性
- 【專題分析】ConstraintLayout 使用
- 【專題分析】搞懂點九圖
- 【專題分析】Adapter
- 【源碼分析】LayoutInflater
- 【源碼分析】ViewStub
- 【源碼分析】View三大流程
- 【源碼分析】觸摸事件分發機制
- 【源碼分析】按鍵事件分發機制
- 【源碼分析】Android窗口機制
- 【面試清單】界面
- 動畫和過渡
- 【基礎知識】動畫和過渡
- 【面試清單】動畫和過渡
- 圖片和圖形
- 【專題分析】圖片加載
- 【面試清單】圖片和圖形
- 后臺任務
- 應用數據和文件
- 基于網絡的內容
- 多線程與多進程
- 【基礎知識】多線程與多進程
- 【源碼分析】Handler
- 【源碼分析】AsyncTask
- 【專題分析】Service
- 【源碼分析】Parcelable
- 【專題分析】Binder
- 【源碼分析】Messenger
- 【面試清單】多線程與多進程
- 應用優化
- 【專題分析】布局優化
- 【專題分析】繪制優化
- 【專題分析】內存優化
- 【專題分析】啟動優化
- 【專題分析】電池優化
- 【專題分析】包大小優化
- 【面試清單】應用優化
- Android新特性
- 【專題分析】狀態欄、ActionBar和導航欄
- 【專題分析】應用圖標、通知欄適配
- 【專題分析】Android新版本重要變更
- 【專題分析】唯一標識符的最佳做法
- 開源庫源碼分析
- 【源碼分析】BaseRecyclerViewAdapterHelper
- 【源碼分析】ButterKnife
- 【源碼分析】Dagger2
- 【源碼分析】EventBus3(一)
- 【源碼分析】EventBus3(二)
- 【源碼分析】Glide
- 【源碼分析】OkHttp
- 【源碼分析】Retrofit
- 其他知識
- Flutter
- 原生開發與跨平臺開發
- 整體歸納
- 狀態及狀態管理
- 零碎知識點
- 添加Flutter到現有應用
- Git知識
- Git命令
- .gitignore文件
- 設計模式
- 創建型模式
- 結構型模式
- 行為型模式
- RxJava
- 基礎
- Linux知識
- 環境變量
- Linux命令
- ADB命令
- 算法
- 常見數據結構及實現
- 數組
- 排序算法
- 鏈表
- 二叉樹
- 棧和隊列
- 算法時間復雜度
- 常見算法思想
- 其他技術
- 正則表達式
- 編碼格式
- HTTP與HTTPS
- 【面試清單】其他知識
- 開發歸納
- Android零碎問題
- 其他零碎問題
- 開發思路