在經過一次沒有準備的面試后,發現自己雖然寫了兩年的android代碼,基礎知識卻忘的差不多了。這是程序員的大忌,沒有扎實的基礎,就只能是copy別人的代碼,實現自己的業務。永遠只是一個最底層的corder。這次的失敗,讓我刻骨銘心!也讓我下決心做一個有思想的程序員!
這是我的開篇之作,從java基礎開始學習。本篇文章大多摘自張拭心的博客 shixinzhang,結識張同學,是因為他在gitchat上分享了他的面試經驗,再看了他的博客文章,從此深深的膜拜!感謝在迷茫的時刻遇到了你
以下是java基礎:
1.內部類、靜態內部類區別、使用場景:
答:
Inner類的實例有Outer的實例的指針(即可以訪問Outer的成員)。而StaticInner類沒有。
內部類的重要作用在于為多重繼承提供支持。
簡單理解就是:如果把類比喻成雞蛋,內部類為蛋黃,外部類是蛋殼。那么靜態類相當于熟雞蛋,就算蛋殼破碎(外部類沒有實例化),蛋黃依然完好(內部類可以實例化);而非靜態類相當于生雞蛋,蛋殼破碎(無實例化),蛋黃也會跟著xx(不能實例化)。
2.抽象類、接口 繼承實現區別:
答:
包含抽象方法的類稱為抽象類,但并不意味著抽象類中只能有抽象方法,它和普通類一樣,同樣可以擁有成員變量和普通的成員方法。注意,抽象類和普通類的主要有三點區別:
1)抽象方法必須為public或者protected(因為如果為private,則不能被子類繼承,子類便無法實現該方法),缺省情況下默認為public。
2)抽象類不能用來創建對象;
3)如果一個類繼承于一個抽象類,則子類必須實現父類的抽象方法。如果子類沒有實現父類的抽象方法,則必須將子類也定義為為abstract類。
接口中所有的方法不能有具體的實現,也就是說,接口中的方法必須都是抽象方法。從這里可以隱約看出接口和抽象類的區別,接口是一種極度抽象的類型,它比抽象類更加“抽象”,并且一般情況下不在接口中定義變量。
語法層面上的區別
1)抽象類可以提供成員方法的實現細節,而接口中只能存在public abstract 方法;
2)抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是public static final類型的;
3)接口中不能含有靜態代碼塊以及靜態方法,而抽象類可以有靜態代碼塊和靜態方法;
4)一個類只能繼承一個抽象類,而一個類卻可以實現多個接口。
設計層面上的區別
1)抽象類是對一種事物的抽象,即對類抽象,而接口是對行為的抽象。抽象類是對整個類整體進行抽象,包括屬性、行為,但是接口卻是對類局部(行為)進行抽象。
2)抽象類作為很多子類的父類,它是一種模板式設計。而接口是一種行為規范,它是一種輻射式設計。
接口可以繼承接口
抽象類可以實現接口(不需要實現接口中的方法,接口是一種特殊的抽象類)
普通類繼承抽象類或實現接口
普通類繼承抽象類:必須實現抽象類的所有抽象方法和該抽象類父類的所有方法
普通類實現接口:必須實現接口及其父接口的全部方法
3.集合
1.Iterator 是一個集合上的迭代器:可以遍歷刪除集合元素
2.CopyOnWriteArrayList 集合快照。通過增強for循環進行刪除集合元素
3.ListIterator 集合迭代器 與Iterator的區別:
1. ListIterator有add()方法,可以向List中添加對象,而Iterator不能
2. ListIterator和Iterator都有hasNext()和next()方法,可以實現順序向后遍歷,
但ListIterator 有hasPrevious()和previous()方法,可以實現逆向(順序向前)遍歷。
Iterator就不可以。
3. ListIterator可以定位當前的索引位置,nextIndex()和previousIndex()可以實現。
Iterator沒有此功能。
4. 都可實現刪除對象,但是ListIterator可以實現對象的修改,set()方法可以實現。
Iierator僅能遍歷,不能修改。
4.Collection 集合的操作:
1.Aggregate Operations 聚合操作:結合lambda使用
Stream<E> stream() 獲取連續流
Stream<E> parallelStream() 獲取并行流
2.并發和并行的概念
5.List集合:List 是一個元素有序的、可以重復、可以為 null 的集合(set不可重復)
6.ArrayList: 本質是一個數組,在元素變化時new一個新的數組
7.LinkedList: 本質是一個雙向鏈表,Link可以動態添加刪除元素
8.List list3 = new ArrayList(list1);list3.addAll(list2);將兩個集合組合在一起,引用地址
沒有變。
9.List 與 Array的區別:
相似之處:
都可以表示一組同類型的對象
都使用下標進行索引
不同之處:
數組可以存任何類型元素
List 不可以存基本數據類型,必須要包裝
數組容量固定不可改變;List 容量可動態增長
數組效率高; List 由于要維護額外內容,效率相對低一些
10.List 與 Array相互轉換:
Arraylist 效率大于LinkList
11.集合的工具類 Collections 中包含很多 List 的相關操作算法:
sort ,歸并排序
shuffle ,隨機打亂
reverse ,反轉元素順序
swap ,交換
binarySearch ,二分查找
……
12.AbstractCollection(abstract):是Java集合框架中Collection接口的一個直接實
現類,Collection下的大多數子類都繼承AbstractCollection,比如List的實現類,
Set的實現類。
13.AbstractList (abstract):繼承自 AbstractCollection 抽象類,實現了 List 接口,是
ArrayList 和AbstractSequentiaList 的父類
1.RandomAccess:標記支持隨機訪問 實現的有:ArrayList, AttributeList,
CopyOnWriteArrayList, Vector, Stack
2.AbstractList特征:
既實現了 List 的期望
也繼承了 AbstractCollection 的傳統
還創建了內部的迭代器 Itr, ListItr
還有兩個內部子類 SubList 和 RandomAccessSublist;
15.ArrayList: 繼承AbstractList實現list<>
迭代器遍歷,如果是并發的環境需要加同步鎖
List list = Collections.synchronizedList(new ArrayList(...));
16.AbstractSequentialList:繼承自 AbstractList,是 LinkedList 的父類,是 List 接口 的簡
化版實現,只支持按次序訪問,實現了ListIterator相關的方法
- Queue 隊列:隊列是數據結構中比較重要的一種類型,它支持 FIFO,尾部添加、
頭部刪除(先進隊列的元素先出隊列),跟我們生活中的排隊類似。繼承
Collection 接口 ,Deque, LinkedList, PriorityQueue, BlockingQueue 等類都實現
了它,Queue 用來存放 等待處理元素 的集合,這種場景一般用于緩沖、并發訪問
18.Queue中的方法:后面的方法在發生異常是不會報錯
1.add(E), offer(E) 在尾部添加: false
2.remove(), poll() 刪除并返回頭部:null
3.element(), peek() 獲取但不刪除: null
注意事項:
1.雖然 LinkedList 沒有禁止添加 null,但是一般情況下 Queue 的實現類
都不允許添加 null 元素,為啥呢?因為 poll(), peek() 方法在異常的時候
會返回 null,你添加了 null 以后,當獲取時不好分辨究竟是否正確返
回。
2.Queue 一般都是 FIFO 的,但是也有例外,比如優先隊列 priority
queue(它的順序是根據自然排序或者自定義 comparator 的);再比如
LIFO 的隊列(跟棧一樣,后來進去的先出去)。不論進入、出去的先
后順序是怎樣的,使用 remove(),poll() 方法操作的都是 頭部 的元素;
而插入的位置則不一定是在隊尾了,不同的 queue 會有不同的插入邏
輯。
19.Deque :是 Double ended queue (雙端隊列) 的縮寫,讀音和 deck 一樣,蛋殼。
一般場景
LinkedList 大小可變的鏈表雙端隊列,允許元素為 null
ArrayDeque 大下可變的數組雙端隊列,不允許 null
并發場景
LinkedBlockingDeque 如果隊列為空時,獲取操作將會阻塞,知道有元素添加
工作密取模式:在生產者-消費者模式中所有消費者都從一個工作隊列中取元素,一般使用阻塞隊 列實現;而在工作密取模式中,每個消費者有其單獨的工作隊列,如果它完成了自己雙端隊列中的 全部工作,那么它就可以從其他消費者的雙端隊列末尾秘密地獲取工作。工作密取模式對比傳統的生產者-消費者 模式,更為靈活,因為多個線程不會因為在同一個工作隊列中搶占內容發生競爭。在大多數時候,它們只是訪問自己的雙端隊列。即使需要訪問另一個隊列時,也是從 隊列的尾部獲取工作,降低了隊列上的競爭程度。
20.LinkedList:繼承自 AbstractSequentialList 接口,同時了還實現了 Deque, Queue
接口。
特點:
雙向鏈表實現
元素時有序的,輸出順序與輸入順序一致
允許元素為 null
所有指定位置的操作都是從頭開始遍歷進行的
和 ArrayList 一樣,不是同步容器List list = Collections.synchronizedList(new LinkedList(...));
區別:
ArrayList
基于數組,在數組中搜索和讀取數據是很快的。因此 ArrayList 獲取數據的時間復雜度是O(1);
但是添加、刪除時該元素后面的所有元素都要移動,所以添加/刪除數據效率不高;
另外其實還是有容量的,每次達到閾值需要擴容,這個操作比較影響效率。
LinkedList
基于雙端鏈表,添加/刪除元素只會影響周圍的兩個節點,開銷很低;
只能順序遍歷,無法按照索引獲得元素,因此查詢效率不高;
沒有固定容量,不需要擴容;
需要更多的內存, LinkedList 每個節點中需要多存儲前后節點的信息,占用空間更多些。
21.Vector: Vector 和 ArrayList 一樣,都是繼承自 AbstractList。它是 Stack 的父類。英文的意
思是 “矢量”
Vector 特點
底層由一個可以增長的數組組成
Vector 通過 capacity (容量) 和 capacityIncrement (增長數量) 來盡量少的占用空間
擴容時默認擴大兩倍
最好在插入大量元素前增加 vector 容量,那樣可以減少重新申請內存的次數
通過 iterator 和 lastIterator 獲得的迭代器是 fail-fast 的
通過 elements 獲得的老版迭代器 Enumeration 不是 fail-fast 的
同步類,每個方法前都有同步鎖 synchronized
在 JDK 2.0 以后,經過優化,Vector 也加入了 Java 集合框架大家族
Vector VS ArrayList
共同點:
都是基于數組
都支持隨機訪問
默認容量都是 10
都有擴容機制
區別:
Vector 出生的比較早,JDK 1.0 就出生了,ArrayList JDK 1.2 才出來
Vector 比 ArrayList 多一種迭代器 Enumeration
Vector 是線程安全的,ArrayList 不是
Vector 默認擴容 2 倍,ArrayList 是 1.5
如果沒有線程安全的需求,一般推薦使用 ArrayList,而不是 Vector,因為每次都要獲取
鎖,效率太低。
21.Stack :Stack繼承自 Vector,它是 數組實現的棧。
Stack 具有以下特點:
繼承自 Vector
有 5 種創建 Stack 的方法
采用數組實現
除了 push(),剩下的方法都是同步的
其實 LinkedList 這個棧的特性也是繼承自 雙端隊列 Deque,官方也推薦在使用棧時優先使
用 Deque,而不是 Stack
22.Map:Map 接口 是和 Collection 接口 同一等級的集合根接口,它 表示一個鍵值對 (key-
value) 的映射。類似數學中 函數 的概念
1.Map 中元素的順序取決于迭代器迭代時的順序,有的實現類保證了元素輸入輸出時的
順序,比如說 TreeMap;有的實現類則是無序的,比如 HashMap。
2.KeySet: KeySet 是一個 Map 中鍵(key)的集合,以 Set 的形式保存,不允許重復,
因此鍵存儲的對象需要重寫 equals() 和 hashCode() 方法。
3.Values 是一個 Map 中值 (value) 的集合,以 Collection 的形式保存,因此可以重
復。
4.Entry : Entry 是 Map 接口中的靜態內部接口,表示一個鍵值對的映射,通過
Map.entrySet()方法獲得的是一組 Entry 的集合,保存在 Set 中,所以 Map 中
的 Entry 也不能重復
getKey() , 獲取這組映射中的鍵 key
getValue() , 獲取這組映射中的值 value
setValue() , 修改這組映射中的值
hashCode() , 返回這個 Entry 的哈希值
equals() , 對比 key-value 是否相等
5.Map的三種遍歷方式:
Set set = map.keySet(); for (Object key : set) { System.out.println(map.get(key)); }
Set entrySet = map.entrySet(); for (Object o : entrySet) { Map.Entry entry = (Map.Entry) o; System.out.println(entry); //key=value System.out.println(entry.getKey() + " / " + entry.getValue()); }
Collection values = map.values(); Iterator iterator = values.iterator(); while (iterator.hasNext()){ System.out.println("value " + iterator.next()); }
6.Map 的實現類主要有 4 種:
Hashtable
古老,線程安全
HashMap
速度很快,但沒有順序
TreeMap
有序的,效率比 HashMap 低
LinkedHashMap
結合 HashMap 和 TreeMap 的有點,有序的同時效率也不錯,僅比 HashMap 慢一點
7.Map特點:
沒有重復的 key
每個 key 只能對應一個 value, 多個 key 可以對應一個 value
key,value 都可以是任何引用類型的數據,包括 null
Map 取代了古老的 Dictionary 抽象類
注意:
可以使用 Map 作為 Map 的值,但禁止使用 Map 作為 Map 的鍵。因為在這么復
雜的 Map 中,equals() 方法和 hashCode() 比較難定義,另一方面,你應該盡量避
免使用“可變”的類作為 Map 的鍵。如果你將一個對象作為鍵值并保存在 Map 中,
之后又改變了其狀態,那么 Map 就會產生混亂,你所保存的值可能丟失。
22.Hash:哈希又稱“散列”。散列(hash)英文原意是“混雜”、“拼湊”、“重新表述”的意思
1.通常使用數組或者鏈表來存儲元素,一旦存儲的內容數量特別多,需要占用很大的空
間,而且在查找某個元素是否存在的過程中,數組和鏈表都需要挨個循環比較,而通
過 哈希 計算,可以大大減少比較次數
2.哈希 其實是隨機存儲的一種優化,先進行分類,然后查找時按照這個對象的分類去
找。通過一次計算大幅度縮小查找范圍,自然比從全部數據里查找速度要快
3.哈希函數:哈希函數是一種映射關系,根據數據的關鍵詞 key ,通過一定的函數關系,
計算出該元素存儲位置的函數(直接定址法,除留余數法,數字分析法,隨機數法...)
4.哈希沖突:選用哈希函數計算哈希值時,可能不同的key會得到相同的結果,一個地址
怎么存放多個數據呢?這就是沖突(鏈接法(拉鏈法),開放定址法,線性探查法)
5.哈希表:實現關聯數組(associative array)的一種數據結構,廣泛應用于實現數據的
快速查找
6.分布式緩存:網絡環境下的分布式緩存系統一般基于一致性哈希(Consistent
hashing)。簡單的說,一致性哈希將哈希值取值空間組織成一個虛擬的環,各個服務
器與數據關鍵字K使用相同的哈希函數映射到這個環上,數據會存儲在它順時針“游走”遇
到的第一個服務器。可以使每個服務器節點的負載相對均衡,很大程度上避免資源的浪
費。在動態分布式緩存系統中,哈希算法的設計是關鍵點。使用分布更合理的算法可以
使得多個服務節點間的負載相對均衡,可以很大程度上避免資源的浪費以及部分服務器
過載。 使用帶虛擬節點的一致性哈希算法,可以有效地降低服務硬件環境變化帶來的數
據遷移代價和風險,從而使分布式緩存系統更加高效穩定。
23.AbstractMap:AbstractMap是Map接口的的實現類之一,也是HashMap, TreeMap,
ConcurrentHashMap 等類的父類。AbstractMap 提供了 Map 的基本實現,使得我們以
后要實現一個 Map 不用從頭開始,只需要繼承 AbstractMap, 然后按需求實現/重寫對應
方法即可。
24.HashMap:HashMap 是一個采用哈希表實現的鍵值對集合,繼承自 AbstractMap,實現了
Map接口 。
1.特點:
底層實現是 鏈表數組,JDK 8 后又加了 紅黑樹
實現了 Map 全部的方法
key 用 Set 存放,所以想做到 key 不允許重復,key 對應的類需要重寫 hashCode 和 equals 方法
允許空鍵和空值(但空鍵只有一個,且放在第一位,下面會介紹)
元素是無序的,而且順序會不定時改變
插入、獲取的時間復雜度基本是 O(1)(前提是有適當的哈希函數,讓元素分布在均勻的位置,發生 沖突采用拉鏈法解決)
遍歷整個 Map 需要的時間與 桶(數組) 的長度成正比(因此初始化時 HashMap 的容量不宜太大)
兩個關鍵因子:初始容量(16)、加載因子(0.75)
除了不允許null 并且同步 Hashtable幾乎跟HashMap相同
2.當 HashMap 中有大量的元素都存放到同一個桶中時,這時候哈希表里只有一個桶,
這個桶下有一條長長的鏈表,這個時候 HashMap 就相當于一個單鏈表,假如單鏈表
有 n 個元素,遍歷的時間復雜度就是 O(n),完全失去了它的優勢。
3.為什么哈希表的容量一定要是 2的整數次冪? :使用減法替代取模,提升計算效率;
為了使不同 hash 值發生碰撞的概率更小,盡可能促使元素在哈希表中均勻地散列。
4.HashMap 中 equals() 和 hashCode() 有什么作用? :HashMap 的添加、獲取時需要
通過key的hashCode()進行hash(),然后計算下標( n-1 & hash),從而獲得要找的同的
位置。當發生沖突(碰撞)時,利用 key.equals() 方法去鏈表或樹中去查找對應節點
1.8jdk支持紅黑樹結構特點:
1.添加時,當桶中鏈表個數超過 8 時會轉換成紅黑樹;
2.刪除、擴容時,如果桶中結構為紅黑樹,并且樹中元素個數太少的話,會進行修
剪或者直接還原成鏈表結構;
3.查找時即使哈希函數不優,大量元素集中在一個桶中,由于有紅黑樹結構,性能
也不會差。
- 紅黑樹 : 紅黑樹本質上是一種二叉查找樹,但它在二叉查找樹的基礎上額外添加了一
個標記(顏色),同時具有一定的規則。這些規則使紅黑樹保證了一種平衡,插入、
刪除、查找的最壞時間復雜度都為 O(logn)。
特點:
1.每個節點要么是紅色,要么是黑色;
2.根節點永遠是黑色的;
3所有的葉節點都是是黑色的(注意這里說葉子節點其實是上圖中的 NIL 節點);
4.每個紅色節點的兩個子節點一定都是黑色;
5.從任一節點到其子樹中每個葉子節點的路徑都包含相同數量的黑色節點
4.注解
1.注解是一種元數據(描述數據的數據)
2.描述作用,不會直接生效,需要在編譯前/運行時獲取注解信息代碼檢查
3.Java 內置的注解:
5個用于通知編譯器信息的注解
@Override :空注解,用于標記那些覆蓋父類方法的方法,如果父類沒有這個方法,或者復
寫的方法訪問權限比父類的權限小,編譯器就會報錯
@Deprecated : 空注解,用于標記那些不應該被使用的代碼,如果使用了過時的代碼,編譯
器會發出警告
@SafeVarargs : 空注解,(varargs 可變參數)用于標記構造函數或者方法,通知編譯器,
這里的可變參數相關的操作保證安全
@FunctionInterface : Java SE 8 出現的,用于通知編譯器,這個類型是 function 接口
@SuppressWarning:抑制錯誤,可以用于標記整個類、某個方法、某個屬性或者某個參
數,用于告訴編譯器這個代碼是安全的,不必警告
強烈建議最小范圍使用這個注解,一旦你在一個比較大的范圍抑制錯誤,可能會把真正的問
題掩蓋了
4 個用于修飾注解的注解
@Documented:讓注解信息出現在 document 中
@Retention : 指出注解如何存儲,支持以下三種參數
RetentionPolicy.SOURCE : 注解只保留在源碼中,編譯時會忽略
RetentionPolicy.CLASS : 更高一級,編譯時被編譯器保留,但是運行時會被 JVM 忽略
RetentionPolicy.RUNTIME : 最高級,運行時會被保留,可以被運行時訪問
@Target :指出注解作用于(修飾)什么對象,支持以下幾種參數
ElementType.TYPE : 作用于任何類、接口、枚舉
ElementType.FIELD : 作用于一個域或者屬性
ElementType.METHOD : 作用于一個方法
ElementType.PARAMTER : 作用于參數
ElementType.CONSTRUCTOR : 作用于構造函數
ElementType.LOCAL_VARIABLE : 作用于本地變量
ElementType. ANNOTATION_TYPE : 作用于注解
ElementType.PACKAGE : 作用于包
@Inherited :當前注解是否可以繼承
- int value()的使用||default的使用
5.注解的作用:
編譯前提示信息:注解可以被編譯器用來發現錯誤,或者清除不必要的警告;
編譯時生成代碼:一些處理器可以在編譯時根據注解信息生成代碼,比如 Java 代碼,xml
代碼等;
運行時處理:我們可以在運行時根據注解,通過反射獲取具體信息,然后做一些操作。
6.注解的使用:
自定義注解:規定處理對象類型,保存階段,以及包含的值
使用注解修飾我們想要的處理的類、方法或者屬性
讀取注解,使用注解處理器處理(運行時處理器,編譯時處理器)
7.運行時處理器:注解 + 反射 ,通過反射得到注解方法需要的值
8.APT;即 Annotation Processing Tool,注解處理工具,它可以在編譯時檢測源代碼文件,找到
符合條件的注解修飾的內容,然后進行相應的處理。
9.編譯時生成代碼過程:
先創建注解
創建注解處理器,在其中拿到注解修飾的變量信息,生成需要的代碼
創建運行時,調用生成代碼的調度器
10.編譯時生成代碼的使用:
用注解修飾變量
編譯時使用注解處理器生成代碼
運行時調用生成的代碼
11.MyButterknife的實現
5.反射
1.Reflection :Java強類型語言,但是我們在運行時有了解、修改信息的需求,包括類信息、成
員信息以及數組信息
- Reflection(反射)Introspection(內省)區別:
內省在運行時檢查一個對象的類型或者屬性:instancesof
反射在運行時檢查或者修改一個對象信息:例如訪問私有方法,動態創建對象
3.反射的入口: java.lang.Class
基本類型,(固定的 8 種) :
整數:byte, short, int, long
小數:float, double
字符:char
布爾值:boolean
引用類型 :
所有的引用類型都繼承自 java.lang.Object
類,枚舉,數組,接口都是引用類型
java.io.Serializable 接口,基本類型的包裝類(比如 java.lang.Double)也是引用類型
對每一種對象,JVM 都會實例化一個 java.lang.Class 的實例,java.lang.Class 為我們提供
了在運行時訪問對象的屬性和類型信息的能力。Class 還提供了創建新的類和對象的能力。
4.如何得到一個Class對象:
1.Object.getClass 方法:僅限于引用類型
2.類名.class 語法: int.class.newInstance()不僅能用于引用類型,基本類型也可以
3.Class.forName():Class<?> c = Class.forName("java.lang.String");通過完整的類路徑得
到,僅限于引用類型
4.靜態屬性 TYPE:Class<Void> voidWrapper = Void.TYPE; 不僅能用于引用類型,基本
類型也可以
5.返回 Class 的方法:
1.Class.getSuperclass() 返回調用類的父類
2.Class.getClasses() 返回調用類的所有公共類、接口、枚舉組成的 Class 數組,包括
繼承的
3.Class.getDeclaredClasses() 返回調用類顯式聲明的所有類、接口、枚舉組成的
Class 數組
4.Class.getDeclaringClass() 返回類
5.java.lang.reflect.Field.getDeclaringClass() 屬性
6.java.lang.reflect.Method.getDeclaringClass() 方法
7.java.lang.reflect.Constructor.getDeclaringClass() 構造器所在的類
6.Class 的修飾符:
1.訪問權限控制符:public, protected, private
2.抽象的、需要實現的:abstract
3.限制只能有一個實例的:static
4.不允許修改的:final
5.線程同步鎖:synchronized
6.原生函數:native
7.采用嚴格的浮點精度:strictfp
8.接口
9.注解
通過 Class.getModifiers() 獲得調用類的修飾符的二進制值,使用 Modifier.toString(int
modifiers) 將二進制值轉換為字符串
Interface 默認是 abstract 的,雖然我們沒有添加,編譯器會在編譯器為每個 Interface
添加這個修飾符。
只有被 @Retention(RetentionPolicy.RUNTIME) 修飾的注解才可以在運行時被發射獲
取
Java 中預定義的注解 @Deprecated,@Override, 和 @SuppressWarnings 中只有
@Deprecated 可以在運行時被訪問到
7.Class 的成員:
1.java.lang.reflect.Constructor:表示該 Class 的構造函數
2.java.lang.reflect.Field:表示該 Class 的成員變量
3.java.lang.reflect.Method:表示該 Class 的成員方法
8.Field 成員變量的反射:
1.獲取成員變量的類型:Filed.getType();Filed.getGenericType()
2.獲取成員變量的修飾符: 同上,線程共享數據的一致性:volatile
3.獲取和修改成員變量的值:得到Filed 然后,file.set()就可以修改成員變量的值
4.常見的錯誤:
1.java.lang.IllegalArgumentException:使用反射獲取或者修改一個變量
值時,編譯器不會進行自動裝/拆箱,需要自己包裝
2.反射非 public的變量導致的 NoSuchFieldException
3.修改 final類型的變量導致的 IllegalAccessException:設置setAccessible(true)
4.在使用反射修改某個對象的成員變量前你要明白,這樣做會造成一定程度的性能開
銷,因為在反射時這樣的操作需要引發許多額外操作,比如驗證訪問權限等
9.Method 方法的反射:
1.繼承的方法(包括重載、重寫和隱藏的)會被編譯器強制執行,這些方法都無法反
射。
2.方法的組成:每個方法都由 修飾符、返回值、參數、注解和拋出的異常組成
3.如何獲取方法的信息: Method[] declaredMethods = cls.getDeclaredMethods();
declaredMethod.getName()); //獲得單獨的方法名
declaredMethod.toGenericString() //獲得完整的方法信息(包括修飾符、返回
值、路徑、名稱、參數、拋出值)
declaredMethod.getModifiers(); //獲得修飾符
declaredMethod.getReturnType()); //獲得返回值
declaredMethod.getGenericReturnType()); //獲得完整信息的返回值
declaredMethod.getParameterTypes(); //獲得參數類型
declaredMethod.getExceptionTypes(); //獲得異常名稱
declaredMethod.getAnnotations(); //獲得注解
4.獲得的方法有三種類型
synthetic method:合成方法 內部類生成的方法
varargs ( variable arguments) method:Java 可變參數方法
bridge method:橋接方法 兼容jdk1.5之前,擦除泛型
5.反射調用方法:Method.invoke();
6.泛型
1.“泛型” 意味著編寫的代碼可以被不同類型的對象所重用。泛型的本質是參數化類
型,也就是說所操作的數據類型被指定為一個參數
2.Object處理不同類型時的缺點:
每次使用時都需要強制轉換成想要的類型
在編譯時編譯器并不知道類型轉換是否正常,運行時才知道,不安全
3.“泛型”引入的目的:
1.類型安全
泛型的主要目標是提高 Java 程序的類型安全
編譯時期就可以檢查出因 Java 類型不正確導致的 ClassCastException 異常
符合越早出錯代價越小原則
2.消除強制類型轉換
泛型的一個附帶好處是,使用時直接得到目標類型,消除許多強制類型轉換
所得即所需,這使得代碼更加可讀,并且減少了出錯機會
潛在的性能收益
3.由于泛型的實現方式,支持泛型(幾乎)不需要 JVM 或類文件更改
所有工作都在編譯器中完成
編譯器生成的代碼跟不使用泛型(和強制類型轉換)時所寫的代碼幾乎一致,
只是更能確保類型安全而已
4."泛型" 的使用方式:類型參數的意義是告訴編譯器這個集合中要存放實例的類型,
從而在添加其他類型時做出提示,在編譯時就為類型安全做了保證。
1.泛型類:泛型類和普通類的區別就是類名后有類型參數列表 <E>如:
public class HashMap<K, V> 泛型類最常見的用途就是作為容納不同類型數
據的容器類,比如 Java 集合容器類。
2.泛型接口:泛型接口在接口名后添加類型參數,接口聲明類型后,接口方法就可
以直接使用這個類型。實現類在實現泛型接口時需要指明具體的參數類型,不
然默認類型是 Object,這就失去了泛型接口的意義
泛型接口比較實用的使用場景就是用作策略模式的公共策略,泛型接口定
義基本的規則,然后作為引用傳遞給客戶端,這樣在運行時就能傳入不
同的策略實現類。
3.泛型方法:泛型方法是指使用泛型的方法,如果它所在的類是個泛型類,
那就很簡單了,直接使用類聲明的參數。如果一個方法所在的類不是泛
型類,或者他想要處理不同于泛型類聲明類型的數據,那它就需要自己
聲明類型
4.泛型的通配符:有時候希望傳入的類型有一個指定的范圍,從而可以進行
一些特定的操作,泛型中有三種通配符形式:
<?> 無限制通配符
<? extends E> extends 關鍵字聲明了類型的上界,表示參數化的類型可
能是所指定的類型,或者是此類型的子類(用于靈活讀取,使得方法
可以讀取 E 或 E 的任意子類型的容器對象)
<? super E> super 關鍵字聲明了類型的下界,表示參數化的類型可能是
指定的類型,或者是此類型的父類(用于靈活寫入或比較,使得對象
可以寫入父類型的容器,使得父類型的比較方法可以應用于子類對
象)
5.泛型的類型擦除:當編譯器對帶有泛型的java代碼進行編譯時,它會去執
行類型檢查和類型推斷,然后生成普通的不帶泛型的字節碼,這種普通的字
節碼可以被一般的 Java 虛擬機接收并執行,這在就叫做 類型擦除(type
erasure)。泛型就是一個語法糖,它運行時沒有存儲任何類型信息.
6.泛型的規則:
泛型的參數類型只能是類(包括自定義類),不能是簡單類型。
同一種泛型可以對應多個版本(因為參數類型是不確定的),不同版本
的泛型類實例是不兼容的。
泛型的類型參數可以有多個
泛型的參數類型可以使用 extends 語句,習慣上稱為“有界類型”
泛型的參數類型還可以是通配符類型
7.泛型的使用場景:
當類中要操作的引用數據類型不確定的時候,過去使用 Object 來完成擴
展,JDK 1.5后推薦使用泛型來完成擴展,同時保證安全性
8.泛型的總結:
1.源碼中仍然有Object類型,是為了兼容,新代碼中用泛型代替
2.泛型是通過擦除來實現的。因此泛型只在編譯時強化它的類型信息
3.如果類型參數在方法聲明中只出現一次,可以用通配符代替它
4.數組中不能使用泛型:array不能保證編譯時類型安全
5.Java 中 List<Object> 和原始類型 List 之間的區別?
在編譯時編譯器不會對原始類型進行類型安全檢查,卻會對帶參數的
類型進行檢查
通過使用 Object 作為類型,可以告知編譯器該方法可以接受任何類
型的對象,比如String 或 Integer
你可以把任何帶參數的類型傳遞給原始類型 List,但卻不能把 List<
String> 傳遞給接受 List< Object> 的方法,因為泛型的不可變
性,會產生編譯錯誤。
7.異常
1.Throwable:Throwable 指定代碼中可用異常傳播機制通過 Java 應用程序
傳輸的任何問題的共性,Exception(異常)和 Error(錯誤)都是它的
子類
Exception(異常):是程序本身可以處理的異常。
Error(錯誤):是程序無法處理的錯誤,表示運行應用程序中較嚴重問
題。大多數錯誤與代碼編寫者執行的操作無關,而表示代碼運行時
JVM(Java 虛擬機)出現的問題。例如,Java虛擬機運行錯誤(Virtual
MachineError),當 JVM 不再有繼續執行操作所需的內存資源時,將出
現 OutOfMemoryError。這些異常發生時,Java虛擬機(JVM)一般會
選擇線程終止。
2.異常的分類:
可查異常:除了RuntimeException及其子類以外,其他的Exception類及
其子類都屬于可查異常。這種異常的特點是Java編譯器會檢查它。發生
這類異常編譯不會通過
不可查異常:運行時異常(RuntimeException與其子類)和錯誤
(Error)
3.處理異常的機制:
1.拋出異常:當一個方法出現錯誤引發異常時,方法創建異常對象并交付
運行時系統,異常對象中包含了異常類型和異常出現時的程序狀態等異
常信息。運行時系統負責尋找處置異常的代碼并執行
2.捕獲異常: 在方法拋出異常之后,運行時系統將轉為尋找合適的異常
處理器(exception handler)。潛在的異常處理器是異常發生時依次存
留在調用棧中的方法的集合。當異常處理器所能處理的異常類型與方法
拋出的異常類型相符時,即為合適 的異常處理器。運行時系統從發生異
常的方法開始,依次回查調用棧中的方法,直至找到含有合適異常處理
器的方法并執行。當運行時系統遍歷調用棧而未找到合適 的異常處理
器,則運行時系統終止。同時,意味著Java程序的終止。
3.一個方法所能捕捉的異常,一定是Java代碼在某處所拋出的異常。簡
單地說,異常總是先被拋出,后被捕捉的。
4.try-catch語句:一旦某個catch捕獲到匹配的異常類型,將進入異常處
理代碼。一經處理結束,就意味著整個try-catch語句結束。其他的catch
子句不再有匹配和捕獲異常類型的機會
5.try-catch-finally語句
try 塊:用于捕獲異常。其后可接零個或多個catch塊,如果沒有catch
塊,則必須跟一個finally塊。
catch 塊:用于處理try捕獲到的異常。若無匹配拋給JVM處理
finally 塊:無論是否捕獲或處理異常,finally塊里的語句都會被執行。當
在try塊或catch塊中遇到return語句時,finally語句塊將在方法返回之前被
執行。在以下4種特殊情況下,finally塊不會被執行:
1)在finally語句塊中發生了異常。
2)在前面的代碼中用了System.exit()退出程序。
3)程序所在的線程死亡。
4)關閉CPU。
6.throws語句:
- 如果是不可查異常(unchecked exception),即Error、
RuntimeException或它們的子類,那么可以不使用throws關鍵字來聲
明要拋出的異常,編譯仍能順利通過,但在運行時會被系統拋出。
2)必須聲明方法可拋出的任何可查異常(checked exception)。即
如果一個方法可能出現受可查異常,要么用try-catch語句捕獲,要么
用throws子句聲明將它拋出,否則會導致編譯錯誤
3)僅當拋出了異常,該方法的調用者才必須處理或者重新拋出該異
常。當方法的調用者無力處理該異常的時候,應該繼續拋出,而不是
囫圇吞棗。
4)調用方法必須遵循任何可查異常的處理和聲明規則。若覆蓋一個
方法,則不能聲明與覆蓋方法不同的異常。聲明的任何異常必須是被
覆蓋方法所聲明異常的同類或子
7.異常鏈:Java方法拋出的可查異常將依據調用棧、沿著方法調用的層
次結構一直傳遞到具備處理能力的調用方法
8.Throwable類中的常用方法:
getCause():返回拋出異常的原因。如果 cause 不存在或未知,則
返回 null。
getMeage():返回異常的消息信息。
printStackTrace():對象的堆棧跟蹤輸出至錯誤輸出流,作為字段
System.err 的值。
9.常見的異常:
- runtimeException子類:
1、java.lang.ArrayIndexOutOfBoundsException數組索引越界異
常。當對數組的索引值為負數或大于等于數組大小時拋出。
2、java.lang.ArithmeticException算術條件異常。譬如:整數除零
等。
3、java.lang.NullPointerException空指針異常。當應用試圖在要
求使用對象的地方使用了null時,拋出該異常。譬如:調用null對象的
實例方法、訪問null對象的屬性、計算null對象的長度、使用throw語
句拋出null等等
4、java.lang.ClassNotFoundException找不到類異常。當應用試
圖根據字符串形式的類名構造類,而在遍歷CLASSPAH之后找不到
對應名稱的class文件時,拋出該異常。
5、java.lang.NegativeArraySizeException 數組長度為負異常
6、java.lang.ArrayStoreException 數組中包含不兼容的值拋出的
異常
7、java.lang.SecurityException 安全性異常
8、java.lang.IllegalArgumentException 非法參數異常
2.IOException
IOException:操作輸入流和輸出流時可能出現的異常。
EOFException 文件已結束異常
FileNotFoundException 文件未找到異常 - 其他
ClassCastException 類型轉換異常類
ArrayStoreException 數組中包含不兼容的值拋出的異常
SQLException 操作數據庫異常類
NoSuchFieldException 字段未找到異常
NoSuchMethodException 方法未找到拋出的異常
NumberFormatException 字符串轉換為數字拋出的異常
StringIndexOutOfBoundsException 字符串索引超出范圍拋出的
異常
IllegalAccessException 不允許訪問某類異常
InstantiationException 當應用程序試圖使用Class類中的
newInstance()方法創建一個類的實例,而指定的類對象無法被實
例化時,拋出該異常
8.IO
1.主要類:
1.File(文件特征與管理):用于文件或者目錄的描述信息,例如生成新目
錄,修改文件名,刪除文件,判斷文件所在路徑等。
2.InputStream(二進制格式操作):抽象類,基于字節的輸入操作,是所有
輸入流的父類。定義了所有輸入流都具有的共同特征。
3.OutputStream(二進制格式操作):抽象類。基于字節的輸出操作。是所
有輸出流的父類。定義了所有輸出流都具有的共同特征。
4.Reader(文件格式操作):抽象類,基于字符的輸入操作。
5.Writer(文件格式操作):抽象類,基于字符的輸出操作。
6.RandomAccessFile(隨機文件操作):一個獨立的類,直接繼承至Object.
它的功能豐富,可以從文件的任意位置進行存取(輸入輸出)操作
2.流的概念:代表任何有能力產出數據的數據源對象或者是有能力接受數據的接
收端對象
流的本質:數據傳輸,根據數據傳輸特性將流抽象為各種類,方便更直觀的進
行數據操作。
流的作用:為數據源和目的地建立一個輸送通道。
Java中將輸入輸出抽象稱為流,就好像水管,將兩個容器連接起來。流是一
組有順序的,有起點和終點的字節集合,是對數據傳輸的總稱或抽象。即數
據在兩設備間的傳輸稱為流.
3.JavaIO設計模型:使用Decorator(裝飾者)模式,按功能劃分Stream,您可以動
態裝配這些Stream,以便獲得您需要的功能。例如,您需要一個具有緩沖的
文件輸入流,則應當組合使用FileInputStream和BufferedInputStream。
4.IO流的分類:
根據處理數據類型的不同分為:字符流和字節流
數據流向不同分為:輸入流和輸出流
按數據來源(去向)分類:
1、File(文件): FileInputStream, FileOutputStream, FileReader,
FileWriter
2、byte[]:ByteArrayInputStream, ByteArrayOutputStream
3、Char[]: CharArrayReader,CharArrayWriter
4、String:StringBufferInputStream, StringReader, StringWriter
、網絡數據流:InputStream,OutputStream, Reader, Writer
5.字符流和字節流:
流序列中的數據既可以是未經加工的原始二進制數據,也可以是經一定編碼
處理后符合某種格式規定的特定數據。因此Java中的流分為兩種:
1) 字節流:數據流中最小的數據單元是字節
2) 字符流:數據流中最小的數據單元是字符, Java中的字符是Unicode編
碼,一個字符占用兩個字節。
字符流的由來:Java中字符是采用Unicode標準,一個字符是16位,即一個
字符使用兩個字節來表示。為此,JAVA中引入了處理字符的流。因為數據編
碼的不同,而有了對字符進行高效操作的流對象。本質其實就是基于字節流
讀取時,去查了指定的碼表
6.輸入流和輸出流:
1) 程序從輸入流讀取數據源。數據源包括外界(鍵盤、文件、網絡…),即是
將數據源讀入到程序的通信通道
2) 程序向輸出流寫入數據。將程序中的數據輸出到外界(顯示器、打印機、
文件、網絡…)的通信通道。
3) 采用數據流的目的就是使得輸出輸入獨立于設備。
輸入流( Input Stream )不關心數據源來自何種設備(鍵盤,文件,網
絡)
輸出流( Output Stream )不關心數據的目的是何種設備(鍵盤,文件,網
絡)
4)相對于程序來說,輸出流是往存儲介質或數據通道寫入數據,而輸入流是從存儲介質
或數據通道中讀取數據,一般來說關于流的特性有下面幾點:
1、先進先出,最先寫入輸出流的數據最先被輸入流讀取到。
2、順序存取,可以一個接一個地往流中寫入一串字節,讀出時也將按寫入順序讀
取一串字節,不能隨機訪問中間的數據。(RandomAccessFile可以從文件的
任意位置進行存取(輸入輸出)操作)
3、只讀或只寫,每個流只能是輸入流或輸出流的一種,不能同時具備兩個功能,
輸入流只能進行讀操作,對輸出流只能進行寫操作。在一個數據傳輸通道中,
如果既要寫入數據,又要讀取數據,則要分別提供兩個流。
7.Java IO流對象:
1.InputStream 輸入字節流: InputStream是所有的輸入字節流的父類,它是一個抽象
類。
1.子類:
ByteArrayInputStream、StringBufferInputStream、FileInputStream是三種基本的
介質流,它們分別從Byte數組、StringBuffer、和本地文件中讀取數據。
PipedInputStream是從與其它線程共用的管道中讀取數據.
ObjectInputStream和所有FilterInputStream的子類都是裝飾流(裝飾器模式的主
角)。
2.InputStream中的三個基本的讀方法:
1.abstract int read() :讀取一個字節數據,并返回讀到的數據,如果返回-1,表示
讀到了輸入流的末尾。
2.intread(byte[]?b) :將數據讀入一個字節數組,同時返回實際讀取的字節數。如果
返回-1,表示讀到了輸入流的末尾。
3.intread(byte[]?b, int?off, int?len) :將數據讀入一個字節數組,同時返回實際讀取
的字節數。如果返回-1,表示讀到了輸入流的末尾。off指定在數組b中存放數據的
起始偏移位置;len指定讀取的最大字節數。
流結束的判斷:方法read()的返回值為-1時;readLine()的返回值為null時。
3.其他方法:
long skip(long?n):在輸入流中跳過n個字節,并返回實際跳過的字節數。
int available() :返回在不發生阻塞的情況下,可讀取的字節數。
void close() :關閉輸入流,釋放和這個流相關的系統資源。
voidmark(int?readlimit) :在輸入流的當前位置放置一個標記,如果讀取的字節數
多于readlimit設置的值,則流忽略這個標記。
void reset() :返回到上一個標記。
booleanmarkSupported() :測試當前流是否支持mark和reset方法。如果支持,返
回true,否則返回false。
2.OutputStream輸出字節流:OutputStream是所有的輸出字節流的父類是一個抽象類
1.子類:
ByteArrayOutputStream、FileOutputStream是兩種基本的介質流,它們分別
向Byte數組、和本地文件中寫入數據。
PipedOutputStream是向與其它線程共用的管道中寫入數據。
ObjectOutputStream和所有FilterOutputStream的子類都是裝飾流。
2.outputStream中的三個基本的寫方法:
abstract void write(int?b):往輸出流中寫入一個字節。
void write(byte[]?b) :往輸出流中寫入數組b中的所有字節。
void write(byte[]?b, int?off, int?len) :往輸出流中寫入數組b中從偏移量off開始
的len個字節的數據。
3其他方法:
void flush() :刷新輸出流,強制緩沖區中的輸出字節被寫出。
void close() :關閉輸出流,釋放和這個流相關的系統資源。
3.Reader字符輸入流:Reader是所有的輸入字符流的父類,它是一個抽象類
1.子類:
1.CharReader、StringReader是兩種基本的介質流,它們分別將Char數組、
String中讀取數據。
2.PipedReader是從與其它線程共用的管道中讀取數據
3.BufferedReader很明顯就是一個裝飾器,它和其子類負責裝飾其它Reader對
象
4.FilterReader是所有自定義具體裝飾流的父類,其子類PushbackReader對
Reader對象進行裝飾,會增加一個行號
5.InputStreamReader是一個連接字節流和字符流的橋梁,它將字節流轉變為
字符流。FileReader可以說是一個達到此功能、常用的工具類,在其源代碼中
明顯使用了將FileInputStream轉變為Reader的方法。我們可以從這個類中得到
一定的技巧。Reader中各個類的用途和使用方法基本和InputStream中的類使
用一致。后面會有Reader與InputStream的對應關系
2.Reader中的主要方法:
(1) public int read() throws IOException; //讀取一個字符,返回值為讀取的字
符
(2) public int read(char cbuf[]) throws IOException; /讀取一系列字符到數組
cbuf[]中,返回值為實際讀取的字符的數量/
(3) public abstract int read(char cbuf[],int off,int len) throws IOException; /讀
取len個字符,從數組cbuf[]的下標off處開始存放,返回值為實際讀取的字
符數量,該方法必須由子類實現/
4.Writer字符輸出流:Writer是所有的輸出字符流的父類,它是一個抽象類
1.子類:
1.CharArrayWriter、StringWriter是兩種基本的介質流,它們分別向Char數
組、String中寫入數據
2.PipedWriter是向與其它線程共用的管道中寫入數據
3.BufferedWriter是一個裝飾器為Writer提供緩沖功能
4.PrintWriter和PrintStream極其類似,功能和使用也非常相似。
5.OutputStreamWriter是OutputStream到Writer轉換的橋梁,它的子類
FileWriter其實就是一個實現此功能的具體類(具體可以研究一
SourceCode)。功能和使用和OutputStream極其類似
2.Writer中的主要方法:
(1) public void write(int c) throws IOException; //將整型值c的低16位寫入輸
出流
(2) public void write(char cbuf[]) throws IOException; //將字符數組cbuf[]寫入
輸出流
(3) public abstract void write(char cbuf[],int off,int len) throws IOException; //
將字符數組cbuf[]中的從索引為off的位置處開始的len個字符寫入輸出流
(4) public void write(String str) throws IOException; //將字符串str中的字符寫
入輸出流
(5) public void write(String str,int off,int len) throws IOException; //將字符串
str 中從索引off開始處的len個字符寫入輸出流
5.字節流的輸入與輸出的對應
1.LineNumberInputStream主要完成從流中讀取數據時,會得到相應的行號,至于
什么時候分行、在哪里分行是由改類主動確定的,并不是在原始中有這樣一個行
號。在輸出部分沒有對應的部分,我們完全可以自己建立一個
LineNumberOutputStream,在最初寫入時會有一個基準的行號,以后每次遇到換
行時會在下一行添加一個行號,看起來也是可以的。好像更不入流了。
2.PushbackInputStream的功能是查看最后一個字節,不滿意就放入緩沖區。主要
用在編譯器的語法、詞法分析部分。輸出部分的BufferedOutputStream幾乎實現相
近的功能。
3.StringBufferInputStream已經被Deprecated,本身就不應該出現在InputStream部
分,主要因為String應該屬于字符流的范圍。已經被廢棄了,當然輸出部分也沒有
必要需要它了!還允許它存在只是為了保持版本的向下兼容而已。
4.SequenceInputStream可以認為是一個工具類,將兩個或者多個輸入流當成一個
輸入流依次讀取。完全可以從IO包中去除,還完全不影響IO包的結構,卻讓其
更“純潔”――純潔的Decorator模式。
5.PrintStream也可以認為是一個輔助工具。主要可以向其他輸出流,或者
FileInputStream寫入數據,本身內部實現還是帶緩沖的。本質上是對其它流的綜合
運用的一個工具而已。一樣可以踢出IO包!System.out和System.out就是
PrintStream的實例!
6.字符流與字節流轉換
轉換流的特點:
1.其是字符流和字節流之間的橋梁
2.可對讀取到的字節數據經過指定編碼轉換成字符
3.可對讀取到的字符數據經過指定編碼轉換成字節
何時使用轉換流?
1.當字節和字符之間有轉換動作時;
2.流操作的數據需要編碼或解碼時。
具體的對象體現:
轉換流:在IO中還存在一類是轉換流,將字節流轉換為字符流,同時可以將字符流
轉化為字節流。
1.InputStreamReader:字節到字符的橋梁
2.OutputStreamWriter:字符到字節的橋梁
OutputStreamWriter(OutStreamout):將字節流以字符流輸出。
InputStreamReader(InputStream in):將字節流以字符流輸入。
這兩個流對象是字符體系中的成員,它們有轉換作用,本身又是字符流,所以在構
造的時候需要傳入字節流對象進來。
7.字節流和字符流的區別(重點)
節流沒有緩沖區,是直接輸出的,而字符流是輸出到緩沖區的。因此在輸出時,字
節流不調用colse()方法時,信息已經輸出了,而字符流只有在調用close()方法關閉
緩沖區時,信息才輸出。要想字符流在未關閉時輸出信息,則需要手動調用flush()
方法。
· 讀寫單位不同:字節流以字節(8bit)為單位,字符流以字符為單位,根據碼表映
射字符,一次可能讀多個字節。
· 處理對象不同:字節流能處理所有類型的數據(如圖片、avi等),而字符流只能
處理字符類型的數據。
結論:只要是處理純文本數據,就優先考慮使用字符流。除此之外都使用字節流。
8.非流式文件類--File類: 從定義看,File類是Object的直接子類,同時它繼承了
Comparable接口可以進行數組的排序。File類的操作包括文件的創建、刪除、重命名、
得到路徑、創建時間等,以下是文件操作常用的函數
File類是對文件系統中文件以及文件夾進行封裝的對象,可以通過對象的思想來操
作文件和文件夾。File類保存文件或目錄的各種元數據信息,包括文件名、文件長
度、最后修改時間、是否可讀、獲取當前文件的路徑名,判斷指定文件是否存在、
獲得當前目錄中的文件列表,創建、刪除文件和目錄等方法。
File類共提供了三個不同的構造函數,以不同的參數形式靈活地接收文件和目錄名
信息。
構造函數:
1)File (String pathname)
例:File f1=new File("FileTest1.txt"); //創建文件對象f1,f1所指的文件是在當前目
錄下創建的FileTest1.txt
2)File (String parent , String child)
例:File f2=new File(“D:\dir1","FileTest2.txt") ;// 注意:D:\dir1目錄事先必須存
在,否則異常
3)File (File parent , String child)
例:File f4=new File("\dir3");
File f5=new File(f4,"FileTest5.txt"); //在如果 \dir3目錄不存在使用f4.mkdir()先創建
一個對應于某磁盤文件或目錄的File對象一經創建, 就可以通過調用它的方法來獲
得文件或目錄的屬性。
1)public boolean exists( ) 判斷文件或目錄是否存在
2)public boolean isFile( ) 判斷是文件還是目錄
3)public boolean isDirectory( ) 判斷是文件還是目錄
4)public String getName( ) 返回文件名或目錄名
5)public String getPath( ) 返回文件或目錄的路徑。
6)public long length( ) 獲取文件的長度
7)public String[ ] list ( ) 將目錄中所有文件名保存在字符串數組中返回。
File類中還定義了一些對文件或目錄進行管理、操作的方法,常用的方法有:
1) public boolean renameTo( File newFile ); 重命名文件
2) public void delete( ); 刪除文件
3) public boolean mkdir( ); 創建目錄
9.RandomAccessFile類
該對象并不是流體系中的一員,其封裝了字節流,同時還封裝了一個緩沖區(字符
數組),通過內部的指針來操作字符數組中的數據。該對象特點:
1.該對象只能操作文件,所以構造函數接收兩種類型的參數:a.字符串文件路徑;
b.File對象。
2.該對象既可以對文件進行讀操作,也能進行寫操作,在進行對象實例化時可指定
操作模式(r,rw)
注意:該對象在實例化時,如果要操作的文件不存在,會自動創建;如果文件存
在,寫數據未指定位置,會從頭開始寫,即覆蓋原有的內容。 可以用于多線程下載
或多個線程同時寫數據到文件
10.System類對IO的支持
·System.in(標準輸入),通常代表鍵盤輸入。
·System.out(標準輸出):通常寫往顯示器。
·System.err(標準錯誤輸出):通常寫往顯示器。
(1)System類不能創建對象,只能直接使用它的三個靜態成員。
(2)每當main方法被執行時,就自動生成上述三個對象。
在Java語言中使用字節流和字符流的步驟基本相同,以輸入流為例,首先創建一個
與數據源相關的流對象,然后利用流對象的方法從流輸入數據,最后執行close()方
法關閉流。