[TOC]
> # 本文關鍵字
> 1. 類、接口、內部類、靜態內部類 ?
> 2. java泛型
> 3. 反射機制
> 4. JAVA垃圾回收機制,java弱引用,軟引用,強引用,虛引用
> 5. IO操作
# 1.類與對象
## 1\. 一些概念
**類的概念:**按照我的理解,與我們日常生活中的類別是相似的,比如人類,蔬菜類,水果類,貓類,狗類等等,雖然比喻不是很恰當,但是卻也很形象!總結來說,**類是一類有相似特征的事物的抽象**。他們有一些相同的行為和屬性。在Java中,類是對數據、方法的封裝,是面向對象編程的體現,提高了數據的封裝性和復用性。
**類的組成:**概括來說是由**屬性(域、變量)和方法**組成的,當然屬性和方法的細分,再次就不在細說了。
**類的分類:**在Java中以class修飾的內部類、靜態內部類、匿名內部類、局部內部類、抽象類以及我們最常用的普通類(暫時就這么叫吧)。
**對象的概念:**對象是一個個是實例,比如說,她叫小紅,那么小紅就是人(Person)類的一個實例,小紅就是Person類的一個**對象**,在自然界中對象是實實在在存在的,那么在Java中,**對象就是類的實例化**。**類是一個抽象的概念,對象是一個具體化的概念。**
**接口的概念:**接口是一種特殊的類,用Interface來修飾。在Java的接口中,如果定義變量就是**靜態常量(static final),**接口中的方法默認是公共的、抽象的,不能實現,接口與類最大的區別**不可被實例化**
## 2\. 抽象類和接口
1. * **抽象類**
* **不能被實例化**,但可以有構造函數,用于在子類構造函數運行時使用
* 用關鍵字 **abstract class** 來定義,跟普通類相似,可以定義任何形式的成員變量
* 抽象類中可以沒有抽象方法(用abstract修飾的方法,沒有方法體),但有抽象方法的類,必須定義為抽象類
* 方法的訪問修飾符沒有限制,有private,protected,public 和默認的(不寫)
* 一個類只能繼承一個抽象類
```
public abstract class AbstractClassExample {
protected int x;
private int y;
public abstract void func1();
public void func2() {
System.out.println("func2");
}
}
public class AbstractExtendClassExample extends AbstractClassExample {
@Override
public void func1() {
System.out.println("func1");
}
}
// AbstractClassExample ac1 = new AbstractClassExample();
// 'AbstractClassExample' is abstract; cannot be instantiated
AbstractClassExample ac2 = new AbstractExtendClassExample();
ac2.func1();
```
* **接口**
* **不能被實例化**,沒有構造函數
* 用關鍵字 **interface** 來定義,定義的成員變量全都是**靜態常量**
* 接口中全都是抽象方法,但不需要寫abstract關鍵字,默認訪問修飾符是public(還可以是protected),可以不寫,但不寫的接口在實現該接口的類上重寫該方法是必須加上public關鍵字
* 接口是類功能的拓展,是對具有相同特征的不同類的功能的一種封裝
* 在Java中一個類只能繼承一個父類,但可以實現多個接口,本類必須實現所有接口中未實現的的方法,否則該類需要被聲明為抽象類
* 接口允許多繼承(僅限于接口)
* 一個類可以實現多個接口
* *jdk1.8之后,接口中可以定義default 方法和 static 方法,需要有具體的方法體實現*
* **抽象類和接口的異同**

* **如何選擇?**
* **使用接口**
* 1. 需要使不相關的類都實現同一個方法
2. 需要實現多繼承的關系
* **使用抽象類**
1. 父類和子類確實有繼承關系,抽象類的方法在其他非繼承關系的類中不需要
2. 需要能夠控制子類的訪問權限,而不是都是public
3. 需要繼承非靜態和非常量的字段
在很多情況下,接口優先于抽象類。因為接口沒有抽象類嚴格的類層次結構要求,可以靈活地為一個類添加行為。并且從 Java 8 開始,接口也可以有默認的方法實現,使得修改接口的成本也變的很低。
有關抽象類和接口的概念可以參考:[https://www.ibm.com/developerworks/cn/java/l-javainterface-abstract/](https://www.ibm.com/developerworks/cn/java/l-javainterface-abstract/ "https://www.ibm.com/developerworks/cn/java/l-javainterface-abstract/")
## 3\. 內部類
Java中內部類分為四種:
* **成員內部類**:在一個類中,顯式定義的一個類,可以用public修飾(但同一個Java文件中,同一個層次級別的class,只能有一個用public修飾),**需要有外部類對象才能實例化內部類對象。**
* **靜態內部類:**用static修飾的內部類,與成員內部類最大的區別在于實例化的時候,不需要外部類實例化對象就可獲取到內部類對象,即直接使用new OutterClassName.InnerClassName( )
```
public class Outter {
//成員內部類
public class InnerClass{
...
}
//靜態內部類
public static class StaticInnerClass {
...
}
public static void main(String[] args) {
//成員內部類實例化方法1
// Parent parent = new Parent();
// InnerClass inner1=parent.new InnerClass();
//成員內部類實例化方法2
InnerClass inner1=new Outter().new InnerClass();
//靜態內部類實例化1
StaticInnerClass inner2=new Outter.StaticInnerClass();
//靜態內部類實例化2
StaticInnerClass inner2=new StaticInnerClass();
}
}
```
* **匿名內部類:**就是沒有名字的內部類。不能是抽象類,必須實現接口或抽象父類的所有抽象方法。
* **局部內部類:**在某個方法內部定義的一個類,有效性只在本方法內。
有關內部類的介紹還可以參考這篇文章: [http://www.cnblogs.com/shen-hua/p/5440285.html](http://www.cnblogs.com/shen-hua/p/5440285.html "http://www.cnblogs.com/shen-hua/p/5440285.html")
## 4\. 枚舉
# 2\. Java泛型
## 1\. 簡介
*(**來自***[***百度百科***](https://baike.baidu.com/item/java%E6%B3%9B%E5%9E%8B/511821?fr=aladdin "百度百科")*)*泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數。這種參數類型可以用在類、接口和方法的創建中,分別稱為**泛型類、泛型接口、泛型方法**。?Java語言引入泛型的好處是安全簡單。在Java SE 1.5之前,沒有泛型的情況的下,通過對類型Object的引用來實現參數的“任意化”,“任意化”帶來的缺點是要做顯式的強制類型轉換,而這種轉換是要求開發者對實際參數類型可以預知的情況下進行的。對于強制類型轉換錯誤的情況,編譯器可能不提示錯誤,在運行的時候才出現異常,這是一個安全隱患。**泛型的好處是在編譯的時候檢查類型安全,并且所有的強制轉換都是自動和隱式的,以提高代碼的重用率**。**泛型只在編譯期有效!**
***注釋:** 類型變量使用大寫形式, 且比較短, 這是很常見的。 在 Java 庫中, 使用變量 E 表示集合的元素類型, K 和 V 分別表示表的關鍵字與值的類型。T(需要時還可以用臨近的字母U和S)表示“任意類型* ”
## 2\. 泛型的分類
* **泛型類**
```
//此處T可以隨便寫為任意標識,常見的如T、E、K、V等形式的參數常用于表示泛型
public class Generic<T>{
//key這個成員變量的類型為T,T的類型由外部指定
private T key;
public Generic(T key) { //泛型構造方法形參key的類型也為T,T的類型由外部指定
this.key = key;
}
public T getKey(){ //泛型方法getKey的返回值類型為T,T的類型由外部指定
return key;
}
}
```
定義的泛型類,就一定要傳入泛型類型實參么?并不是這樣,在使用泛型的時候如果傳入泛型實參,則會根據傳入的泛型實參做相應的限制,此時泛型才會起到本應起到的限制作用。如果不傳入泛型類型實參的話,在泛型類中使用泛型的方法或成員變量定義的類型可以為任何的類型。
* **泛型接口**
泛型接口與泛型類的定義及使用基本相同
```
//定義一個泛型接口
public interface Generator<T> {
public T next();
}
```
* **泛型方法**
泛型方法可以定義在泛型類中也可以定義在普通類中

```
public class GenericTest {
//這個類是個泛型類
public class Generic<T> {
private T key;
public Generic(T key) {
this.key = key;
}
//該方法使用了泛型,但是這并不是一個泛型方法。
//這只是類中一個普通的成員方法,只不過他的返回值是在聲明泛型類已經聲明過的泛型。
//所以在這個方法中才可以繼續使用 T 這個泛型。
public T getKey() {
return key;
}
/**
* 這個方法顯然是有問題的,在編譯器會給我們提示這樣的錯誤信息"cannot reslove symbol E"
* 因為在類的聲明中并未聲明泛型E,所以在使用E做形參和返回值類型時,編譯器會無法識別。
public E setKey(E key){
this.key = keu
}
*/
}
/* --------------------------------泛型類定義結束-------------------------------------- */
/**
* 這才是一個真正的泛型方法。
* 首先在public與返回值之間的<T>必不可少,這表明這是一個泛型方法,并且聲明了一個泛型T
* 這個T可以出現在這個泛型方法的任意位置.
* 泛型的數量也可以為任意多個
* 如:public <T,K> K showKeyName(Generic<T> container){
* ...
* }
*/
public <T> T showKeyName(Generic<T> container) {
System.out.println("container key :" + container.getKey());
//當然這個例子舉的不太合適,只是為了說明泛型方法的特性。
T test = container.getKey();
return test;
}
//這也不是一個泛型方法,這就是一個普通的方法,只是使用了Generic<Number>這個泛型類做形參而已。
public void showKeyValue1(Generic<Number> obj) {
Log.d("泛型測試", "key value is " + obj.getKey());
}
//這也不是一個泛型方法,這也是一個普通的方法,只不過使用了泛型通配符?
//同時這也印證了泛型通配符章節所描述的,?是一種類型實參,可以看做為Number等所有類的父類
public void showKeyValue2(Generic<?> obj) {
Log.d("泛型測試", "key value is " + obj.getKey());
}
/**
* 這個方法是有問題的,編譯器會為我們提示錯誤信息:"UnKnown class 'E' "
* 雖然我們聲明了<T>,也表明了這是一個可以處理泛型的類型的泛型方法。
* 但是只聲明了泛型類型T,并未聲明泛型類型E,因此編譯器并不知道該如何處理E這個類型。
public <T> T showKeyName(Generic<E> container){
...
}
*/
/**
* 這個方法也是有問題的,編譯器會為我們提示錯誤信息:"UnKnown class 'T' "
* 對于編譯器來說T這個類型并未項目中聲明過,因此編譯也不知道該如何編譯這個類。
* 所以這也不是一個正確的泛型方法聲明。
* public void showkey(T genericObj){
* <p>
* }
*/
}
```
## 3\. 泛型的限定
* ```
//這樣類中的泛型T只能是Collection接口的實現類,傳入非Collection接口編譯會出錯
class GenericsFoo<T extends Collection>{
...
}
```
**注意:**<T extends Collection>這里的限定使用[關鍵字](https://baike.baidu.com/item/%E5%85%B3%E9%94%AE%E5%AD%97 "關鍵字")extends,后面可以是類也可以是接口。但這里的extends已經不是繼承的含義了,應該理解為T類型是實現Collection接口的類型,或者T是繼承了XX類的類型。雖然Java泛型簡單的用 extends 統一的表示了原有的 extends 和 implements 的概念,但仍要遵循應用的體系,Java 只能繼承一個類,但可以實現多個接口,所以你的某個類型需要用 extends 限定,且有多種類型的時候,只能存在一個是類,并且類寫在第一位,接口列在后面,也就是:
```
<T extends SomeClass & interface1 & interface2 & interface3>
```
* 示例
```
//定義一個泛型類,泛型的類型只能是Collection的子類
//問題:我們該如何去實例化這個類呢?
public class CollectionGenFoo<T extends Collection> {
private T x;
public CollectionGenFoo(T x) {
this.x = x;
}
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public static void main(String args[]) {
//這樣實例化可以嗎?
CollectionGenFoo<Collection> listFoo1 = null;
listFoo1=new CollectionGenFoo<ArrayList>(new ArrayList());
}
}
```
很遺憾,這樣的定義是**不可以**的!我們必須要把兩個地方寫的是一樣的才可以也就是這樣的
```
CollectionGenFoo<Collection> listFoo1 = null;
listFoo1=new CollectionGenFoo<Collection>(new ArrayList());
//或者
CollectionGenFoo<ArrayList> listFoo1 = null;
listFoo1=new CollectionGenFoo<ArrayList>(new ArrayList());
```
那當我們有了上方的需求怎么辦呢?Java中引入了通配符的概念,下面簡單介紹一下通配符泛型
## 4\. 通配符泛型
* 直接上代碼:
```
CollectionGenFoo<?> listFoo1 = null;
listFoo1=new CollectionGenFoo<ArrayList>(new ArrayList());
```
為了解決類型被限制死了不能動態根據實例來確定的缺點,引入了“通配符泛型”,針對上面的例子,使用通配泛型格式為<? extends Collection>,“?”代表未知類型,這個類型是實現Collection接口的
## 5\. 類型擦除
由于虛擬機中沒有泛型類型對象—所有對象都屬于普通類,所以在代碼編譯后,泛型將被擦除,如果調用時,限定了泛型,則就以限定的類型進行替換,如果沒有限定泛型類型,則以Object進行替換。
## 6\. 注意事項
* **泛型只在編譯期間有效**
* 所有的泛型必須是類(引用)類型,包含自定義類,不能是基本數據類型
* 泛型方法在聲明的時候會聲明泛型,因此即使在泛型類中并未聲明泛型,編譯器也能夠正確識別泛型方法中識別的泛型
* 如果只指定了<?>,而沒有extends,則默認是允許Object及其下的任何Java類了。也就是任意類
* 通配符泛型不單可以向上限制,如<? extends Collection>,還可以向下限制,如<? super Double>,表示類型只能接受Double及其上層父類類型,如Number、Object類型的實例
* 在 Java SE 7 及以后的版本中, 構造函數中可以省略泛型類型:**ArrayList<String> files = new ArrayList<>();**省略的類型可以從變量的類型推斷得出。
參考學習文檔:[https://www.cnblogs.com/coprince/p/8603492.html](https://www.cnblogs.com/coprince/p/8603492.html "https://www.cnblogs.com/coprince/p/8603492.html")
# 3、Java垃圾回收機制
## 1\. 一些概念:
1. 意義:可以有效的防止內存泄露,有效的使用空閑的內存
2. 內存泄漏:在Java中指的是對象使用完之后,沒有被回收,但該對象也沒有用了,導致內存空間被浪費,該對象被稱為“游離對象”
3. 內存溢出:在Java對象創建過程中,剩下的內存空間小于對象所需要的內存空間
## 2\. Java的四種引用類型
1. **強引用(StrongReference)**
在Java代碼中,強引用隨處可見,我們平常的賦值語句就屬于強引用,如:
```
Object object = new Object();?
String str = “hello”;?
```
代碼測試:



Java的垃圾回收機制寧愿拋出OOM(Out Of Memory)內存溢出的異常,也不愿意回收此類對象
2. **軟引用(SoftReference)**
當內存足夠使用時,垃圾回收機制是不會去主動回收此類對象的
**用途:緩存**


通過運行結果可以看出,打印出了最后一個對象,但是之前的對象卻是Null,表明之前的對象已經被垃圾回收機制回收了
3. **弱引用(WeakReference)**
不管內存是否充足,只要垃圾回收機制發現了弱引用對象,就會將其回收
**用途:用于解決內存泄漏的問題**
4. **虛引用(PhantomReference)**
虛引用與其它幾種引用都不同,虛引用并不會決定對象的生命周期.如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收,虛引用主要用來跟蹤對象被垃圾回收器回收的活動.虛引用必須和引用隊列 (ReferenceQueue)聯合使用. 垃圾回收器回收對象時,該對象還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯的引用隊列中。
# 3\. 什么樣的對象會被垃圾回收機制回收?
> 簡單來說,垃圾回收機制會回收那些沒有被引用的對象。如:垃圾回收機制使用了一種引用計數器的算法,在對象被創建時給對象分配一個計數器變量,數值設為1,當任何其它變量被賦值為這個對象的引用時,計數加1(如a?=?b,則b引用的對象實例的計數器+1),當一個對象實例的某個引用超過了生命周期或者被設置為一個新值時,對象實例的引用計數器減1,垃圾回收機制會回收所有的引用計數器為0的變量
# 4、Java的IO操作

由上述圖片可知,Java中的IO流分為兩大部分:
按照處理的類型分為:字符流和字節流
在使用過程中,除了處理字符串或文本類型時,優先使用字符流,其他所有的類型都使用字節流
按照數據流的方向分為:輸入流(InputStream和Reader)和輸出流(OutputStream和Writer)
輸入流只能進行讀操作,輸出流只能進行寫操作
> 參考資料:[http://www.runoob.com/java/java-files-io.html](http://www.runoob.com/java/java-files-io.html "http://www.runoob.com/java/java-files-io.html")