集合:Collection體系、Map體系。java
Collection體系:單列集合的共性操做規則。windows
List:列表,能夠重複,有下標,擁有特有的迭代器ListIterator。數組
ArrayList:底層是可變數組。增刪慢,查詢快。不安全安全
LinkedList:底層是鏈表結構,增刪快,查詢慢。不安全。有頭和尾,特有的頭尾操做的方法。能夠模數據結構
擬數據結構(堆棧、隊列)。學習
Vector:底層是可變數組,增刪,查詢都慢。安全。被ArrayList代替。this
Enumeration:它是古老的迭代器,被Iterator代替。spa
Set:不能存放重複元素。操作系統
HashSet:底層是哈希表。不保證存取的順序。保證對象惟一須要依賴對象的hashCode和equals方法。3d
所以給HashSet中存放的對象須要重寫Object類中的hashCode和equals方法。
TreeSet:底層是二叉樹結構。保證對象惟一和排序須要依賴對象的比較方法(compareTo),對象要具
備比較方法,須要實現Comparable接口。
若是對象具有的比較功能不適合需求,或者對象自己不具有比較功能,這時咱們能夠本身指定比較器對象(Comparator)。而後將這個對象傳遞給TreeSet集合。
LinkedHashSet:它是HashSet的子類,底層是哈希表和鏈表組合。它能夠保證存取的順序。
Map體系:雙列集合的共性操做規則。存放的是具備必定對應關係的數據。key值是不能重複的。
HashMap:底層是哈希表,不保證存取順序。主要做用在key上。key是自定義對象,須要複寫hashCode
和equals方法。
TreeMap:底層是二叉樹,做用在key上。key是自定義對象,須要實現Comparable接口,或者給集合
傳遞Comparator對象。
Hashtable:它底層是哈希表,安全。被HashMap代替。
LinkedHashMap:它是HashMap的子類,能夠保證存取的順序。底層鏈表和哈希表。
Map集合的遍歷,不能直接使用Iterator,而須要將Map集合轉成單列集合。
keySet方法,將Map中的全部key取出存放在Set集合中。遍歷Set集合,獲得每一個key值,而後調用Map中的get方法,進而獲取到key對應的value值。
entrySet方法。將Map中的key和value組成Entry對象(key和value對應關係對象)。存儲在set中,遍歷set集合,獲得Entry對象,而後調用getKey和getValue方法獲得key和value。
values方法:獲取到的是Map中的全部value值,存放在Collection集合中。
能夠存放重複元素:
ArrayList:主要用在查詢較多的時候。
LinkedList:主要是根據頭尾操做時。
Vector:基本不用
不能夠出現重複元素:
HashSet: 對數據的存取順序沒有要求
LinkedHashSet:保證存取順序
TreeSet:對其中的數據排序
數據具備對應關係:
HashMap: 對數據的存取順序沒有要求
TreeMap: 對其中的數據排序
Hashtable: 基本不用
LinkedHashMap:保證存取順序
在使用集合的時候,因爲集合中存放的元素沒有作任何的限制,所以能夠將任何對象保存到集合中。這樣會致使在從集合中取出對象的時候,對象都被提高爲Object類型,若是須要使用對象的特有方法,這時須要向下轉型,就有可能發生類型轉換異常。
、
集合是容器,數組也是容器,可是數組容器一旦定義完成以後,其中可以存放的數據類型就必定肯定,若是在給數組中存放元素的時候,類型和數組限定的類型不匹配,這時編譯就直接報錯
上述集合和數組的差別,是由於集合中的元素沒有進行類型的限定。
咱們能夠想辦法給集合中可以存儲的元素進行類型的限定,這樣若是在給集合中存儲元素的時候,類型與限定的類型不一致,就不讓程序編譯經過。只要程序可以編譯經過,確定集合中保存的類型是限定的類型。這樣在取出的時候,咱們確定知道取出的元素是什麼類型。
解決上述的問題,須要使用JDK中提供的泛型技術。泛型實際上是在限定數據類型的。
泛型的書寫格式:
<引用數據類型>
泛型在使用的時候,主要是限定數據類型,程序中加入泛型以後,操做數據的時候,類型必定要和泛型中指定的類型一致。泛型中不能書寫基本數據類型(使用對應的包裝類型)。
1 * 2 * 泛型技術演示 3 */ 4 5 //自定義比較器 6 class MyComparator implements Comparator<String>{ 7 8 public int compare(String o1, String o2) { 9 int temp = o1.length() - o2.length(); 10 return temp == 0 ? o1.compareTo(o2) : temp; 11 } 12 } 13 public class GeneratorDemo { 14 public static void main(String[] args) { 15 16 //演示泛型在集合中的使用 泛型的菱形技術 17 TreeSet<String> set = new TreeSet<String>( new MyComparator() ); 18 19 set.add("aaaaa"); 20 set.add("aba"); 21 set.add("cb"); 22 set.add("ABC"); 23 set.add("CCB"); 24 set.add("ICBC"); 25 26 //遍歷 27 for (Iterator<String> it = set.iterator(); it.hasNext();) { 28 //String s = it.next(); 29 System.out.println(it.next()); 30 } 31 } 32 }
a、 泛型的菱形技術:在定義類型的時候聲明的泛型的類型,後面建立對象時須要指定的泛型類型能夠省略。
b、 泛型的擦除技術:泛型技術屬於編譯時期的技術。當前程序編譯完成以後,泛型所有被刪除。
泛型技術在程序可以使用,緣由是在使用的類或者接口上提供書寫泛型的地方。若是類或者接口上沒有提供書寫泛型的地方,在實際代碼中咱們也不能書寫。
咱們本身來模擬JDK中能夠書寫泛型的類或者接口。
咱們本身定義類或者接口的時候,聲明<變量>泛型,當在使用這個類或者接口的時候就能夠指定具體的類型。
1 /* 2 * 自定義泛型類: 3 * 定義的類上聲明泛型。 4 */ 5 /* 6 * 需求:定義類,封裝任意類型的數據 7 * 分析: 8 * 能夠在類中定義Object類型的變量,接收任意類型的數據 9 * 可是給調用者返回這個數據的時候,數據就被提高成Object類型 10 * 調用者須要本身手動的再向下轉型。 11 * 12 * 咱們能夠在定義類的時候,在類上定義泛型,讓調用者本身類聲明保存的數據類型。 13 * 14 * class Data<T> : 在定義類的時候,在類上定義一個泛型參數。 15 * 當使用者使用這類的時候,會指定當前這個參數的類型。 16 * 例如:Data<String> d = new Data<String>(); 17 * 咱們定義的類上的泛型T就被String代替。 18 * 19 * 在類上定義的泛型參數,其實就是一個數據類型,只是尚未被使用的時候 20 * 咱們不知道是什麼類型,可是調用者只要建立對象,就會明確這個類型, 21 * 只要程序在運行,泛型類型確定就已經明確。 22 * 所以在類上定義的泛型參數,在類中的任意地方均可以使用。 23 */ 24 class Data<T>{ 25 26 private T data; 27 28 public T getData() { 29 return data; 30 } 31 32 public void setData(T data) { 33 this.data = data; 34 } 35 } 36 37 38 public class Demo2 { 39 public static void main(String[] args) { 40 41 Data<Integer> d = new Data<Integer>(); 42 d.setData(123); 43 44 } 45 }
總結:
泛型類:在定義類的時候,定義泛型參數。在類上定義的泛型參數,在類中可使用。
類上定義的泛型參數,須要在 建立這個類對象的時候明確,若是沒有明確這個類型,默認是Object
類型。
方法的定義格式:
修飾符 返回值類型 方法名( 參數類型 變量名 , 參數類型 變量名 ...... ){
方法體
}
方法上定義的泛型格式:
修飾符 <泛型參數> 返回值類型 方法名( 參數類型 變量名 , 參數類型 變量名 ...... ){
方法體
}
1 /* 2 * 泛型方法: 3 * 類上能夠定義泛型,在類中是可以直接使用類上定義的泛型。 4 * 5 * 在類中也能夠不使用類上的泛型。 6 */ 7 //類上定義泛型 8 class Test2<W>{ 9 10 //在方法上使用泛型 11 public void show(W w){ 12 System.out.println(w); 13 } 14 15 //方法上也能夠不使用類上的泛型 16 public void method(int a){ 17 18 } 19 /* 20 * 若是方法上接收的參數類型也不肯定,可是咱們知道方法上 21 * 接收的參數類型和類上定義的泛型的類型不一致, 22 * 這時能夠在方法上單獨去定義適合這個方法本身的泛型 23 * 24 */ 25 public <Q> void function( Q q ){ 26 System.out.println(q); 27 } 28 29 } 30 public class Demo3 { 31 public static void main(String[] args) { 32 33 Test2<Double> t = new Test2<Double>(); 34 //使用擁有泛型的方法 35 t.function('a'); 36 37 } 38 }
靜態方法不能使用類上定義的泛型。由於類上的泛型類型須要在建立這個類的對象時明確。而靜態方法運行時候能夠沒有對象。
在定義接口的時候,能夠在接口上定義泛型參數。
1 /* 2 * 演示接口上定義泛型 3 */ 4 //在接口上定義了泛型參數 5 interface Inter<P>{ 6 public void show(P p); 7 } 8 /* 9 * 接口的實現類,在實現接口的時候,明確接口上泛型的具體數據類型 10 */ 11 class InterImpl implements Inter<String>{ 12 13 public void show(String p) { 14 15 } 16 }
接口上的泛型:在實現接口的時候明確具體的數據類型。
interface Collection<E>{}
interface List<E> extends Collection<E>{}
class ArrayList<E> implements List<E>{}
開發者本身的類:ArrayList<String> list = new ArrayList<String>();
1 /* 2 * 演示泛型的通配符技術: 3 * 通配符:通通都匹配的符號。使用一個符號去匹配其餘的數據。這個符號被稱爲通配符 4 * 5 * 泛型的通配符符號:?號 ;當接收的數據的時候,若是須要使用泛型,殊不知道當前應該 6 * 書寫什麼數據類型的時候,這時可使用?表示。 7 */ 8 public class GenericTest { 9 public static void main(String[] args) { 10 11 List<String> list = new ArrayList<String>(); 12 Collections.addAll(list, "aa", "bb", "cc", "dd"); 13 printCollection(list); 14 15 Set<Integer> set = new HashSet<Integer>(); 16 Collections.addAll(set, 11, 22, 33, 44, 55, 66, 77); 17 // 打印集合 18 printCollection(set); 19 } 20 21 //泛型的通配符 22 public static void printCollection( Collection<?> list ) { 23 // 打印集合 24 for (Iterator it = list.iterator(); it.hasNext();) { 25 System.out.println(it.next()); 26 } 27 } 28 29 }
1 /* 2 * 演示泛型的通配符技術: 3 * 通配符:通通都匹配的符號。使用一個符號去匹配其餘的數據。這個符號被稱爲通配符 4 * 5 * 泛型的通配符符號:?號 ;當接收的數據的時候,若是須要使用泛型,殊不知道當前應該 6 * 書寫什麼數據類型的時候,這時可使用?表示。 7 */ 8 public class GenericTest2 { 9 public static void main(String[] args) { 10 11 List<Teacher> list = new ArrayList<Teacher>(); 12 list.add(new Teacher("老唐",18)); 13 list.add(new Teacher("老張",28)); 14 list.add(new Teacher("花和尚",38)); 15 list.add(new Teacher("聖手書生",28)); 16 //printCollection(list); 17 18 19 Set<Student> set = new HashSet<Student>(); 20 set.add(new Student("班長",38)); 21 set.add(new Student("班花",18)); 22 set.add(new Student("班草",28)); 23 set.add(new Student("班導",48)); 24 printCollection(set); 25 26 27 Set<Person> set2 = new HashSet<Person>(); 28 set2.add(new Person("班長",38)); 29 set2.add(new Person("班花",18)); 30 set2.add(new Person("班草",28)); 31 set2.add(new Person("班導",48)); 32 printCollection(set2); 33 34 } 35 /* printCollection( Collection<?> coll ) 這個方法能夠接收任何的Collection下的集合容器 36 * 而且能夠將其中的說打印出來。 37 * 38 * printCollection 只打印集合中保存的數據是Person或者Person的子類數據 39 * 若是傳遞的集合中給出的數據不是Person或者Person的子類,就不接受這樣的數據。 40 * 41 * 泛型的限定: 42 * 上限限定: ? extends E 當前的?表示的數據類型能夠是E類型,也能夠是E的子類類型 43 * 例如:? extends Person 當前的?能夠是Person類型或者Person的子類類型 44 * 45 * 下限限定:? super E 當前的?表示的數據類型能夠是E自己類型,或者E的父類類型 46 * 例如:? super Student 當前的?能夠是Student類型或者Student的父類類型, 47 * 但不能是Student的子類或者兄弟類型 48 * 49 * TreeSet(Comparator<? super E> comparator) 50 * TreeSet(Collection<? > c) 51 * 52 * public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) 53 */ 54 public static void printCollection( Collection<? super Student> coll ) { 55 56 for (Iterator it = coll.iterator(); it.hasNext();) { 57 System.out.println(it.next()); 58 } 59 } 60 61 }
class TreeSet<E>{
public TreeSet( Collection<? exntends E> c ){
}
}
當在程序中咱們建立TreeSet集合對象的時候,須要明確TreeSet上定義的泛型的具體類型。若是已經明確的了具體的類型,那麼構造方法上使用的E,就能夠明確的類型一致。
建立TreeSet對象:
TreeSet<Person> set = new TreeSet<Person>( 傳遞集合數據 );
就意味着TreeSet集合中全部使用E的地方都會變成Person類型。
構造方法上的Collection<? extends Person> ,限定當前能夠給集合中保存的數據是Person或者Person的子類。
上面是TreeSet的構造方法,它的目的是在建立TreeSet集合對象的時候,將Collection集合中的數據添加到TreeSet集合中。
而建立TreeSet集合時咱們設定集合中添加的數據類型應該Person類型,那麼就說明Collection中的元素可以添加到TreeSet中,Collection中的數據要麼是Person類型,要麼是Person子類類型。
建立TreeSet對象的時候,會明確E的類型,同時還能夠給TreeSet傳遞一個比較器對象。
傳遞的比較器是用來比較正要給集合中保存的數據和已經在集合中的數據的大小。
TreeSet<Student> set = new TreeSet< Student >(); 聲明TreeSet上的泛型E爲Student類型。
set.add(new Student(「zs」,23));
set.add(new Student(「ls」,33));
至關於要把第二個Student和第一個Student對象傳遞給Comparator中的compare方法進行比較大小。
compare方法須要接收當前這兩個Student對象。
public int compare( Person o1 , Person o2 ){
}
Comparator接口中的compare方法主要任務的接收給集合中存儲的元素和已經在集合中的元素數據,而後對其進行比較。
compare方法上負責接收2個對象的那個類型能夠和集合中的數據類型一致,或者是集合中數據類型的父類型也能夠。
所以得出:TreeSet構造方法上傳遞的Comparator接口能夠接收的數據類型能夠和集合一致,或者集合中的數據類型的父類類型。
咱們的數據所有存儲在計算機的內存中。當程序運行結束以後,數據就所有消失。下次程序啓動的時候,若是須要上次運行的結果數據,這時是沒法獲取到的。
咱們須要在 程序中加入其它的技術,將程序中的有效的數據長久的保存起來,之後程序啓動的時候能夠讀取這些數據,接着進行處理。
須要將數據長久保存,就須要使用Java中提供的IO技術。
IO技術:
I:Input 輸入,讀取操做
O:Output 輸出,寫操做。
數據從其餘的設備上被加載到內存中的這個過程被稱爲輸入(讀取)操做。
數據從內存中輸出到其餘的設備上的這個過程被稱爲輸出(寫)操做。
一、 學習如何操做硬盤上的文件或者文件夾
二、 學習如何讀寫文件中的數據。
注意:IO操做中的數據方向,而後肯定最後須要使用的類或接口中的方法。
數據須要保存在文件中,而文件多了,就須要文件夾進行管理。也就是說文件或者文件夾是咱們長久保存數據的設備上存在的一類事物。
Java確定會有一個類多這個事物進行描述。
Java中使用File類描述文件或者文件夾這個事物。
只要在java中須要操做硬盤上的文件或者文件夾就應該使用File類。
1 /* 2 * 演示File類中的構造方法 3 */ 4 public class FileConstructorDemo { 5 public static void main(String[] args) { 6 method3(); 7 } 8 /* 9 * File(File parent, String child) 10 * File parent 已經將父目錄封裝成File對象, 11 * String child 文件或者文件夾 12 */ 13 public static void method3() { 14 15 //封裝的父目錄 16 File dir = new File("d:/abc/bbb/ccc"); 17 18 //將父目錄下的文件或文件夾封裝成File對象 19 File file = new File(dir , "1.txt"); 20 21 System.out.println(file); 22 } 23 /* 24 * File(String parent, String child) 25 * String parent 當前文件或者文件夾所在的父目錄 26 * String child 是當前的文件或者文件夾 27 * 注意: 28 * 在windows中,目錄(文件夾)之間的使用的是\ 做爲默認分隔符 29 * 咱們能夠可使用 / 做爲分隔符 30 */ 31 public static void method2() { 32 33 //建立File對象 34 File file = new File("d:/abc","1.txt"); 35 36 System.out.println(file); 37 } 38 /* 39 * File(String pathname) 40 * new File("d:/1.txt") 將指定的字符串中的數據封裝成File對象 41 * 可是這個字符串中表示的文件或者文件夾究竟是否真實存在, 42 * 建立File對象的時候不會去驗證 43 */ 44 public static void method() { 45 46 //建立File對象 47 File file = new File("d:/1.txt"); 48 49 System.out.println(file); 50 } 51 }
1 /* 2 * 演示File類中的 獲取 方法 3 * 4 * 舉例說明: 5 * 絕對路徑:上海市閔行區浦江鎮三魯公路3279號明浦廣場3號樓1樓125室 6 * 相對路徑:三魯公路3279號明浦廣場3號樓1樓125室 7 * 8 * 絕對路徑: 9 * 文件或文件所在的全路徑。 10 * 相對路徑: 11 * 文件或文件夾相對其餘文件而言的路徑。 12 * 13 * 例如: 14 * "1.txt" 這時並無說明文件具體在哪一個目錄中, 15 * 這時JVM會認爲當前的這個文件是相對當前程序所在的項目而言。 16 * "d:/1.txt" 全路徑。這時JVM就已經能夠識別這個目錄的具體位置 17 * /1.txt 它相對的是當前項目所在的文件系統的根目錄而言。 18 * 19 */ 20 public class FileGetMethodDemo { 21 public static void main(String[] args) throws IOException { 22 23 File file = new File("abc/1.txt"); 24 25 //getAbsolutePath 獲取到的是File對象保存的文件或者文件所在的全路徑 26 System.out.println("getAbsolutePath="+file.getAbsolutePath()); 27 System.out.println("getAbsoluteFile="+file.getAbsoluteFile()); 28 // getCanonicalPath 獲取到的全路徑中的真實目錄 29 System.out.println("getCanonicalPath="+file.getCanonicalPath()); 30 //getName 獲取到的是File對象中封裝的最後一級的名稱 31 System.out.println("getName="+file.getName()); 32 // getParent 獲取到的最後一級目錄以前的全部目錄 33 System.out.println("getParent="+file.getParent()); 34 System.out.println("getParentFile="+file.getParentFile()); 35 36 System.out.println("getFreeSpace="+file.getFreeSpace()); 37 System.out.println("getTotalSpace="+file.getTotalSpace()); 38 System.out.println("getUsableSpace="+file.getUsableSpace()); 39 40 //獲取操做系統全部的根目錄,windows 全部的盤符 41 File[] roots = File.listRoots(); 42 for (File root : roots) { 43 System.out.println(root); 44 } 45 } 46 }
注意:delete方法不走回收站,慎用
6. 判斷方法
1 /* 2 * 演示File類中的判斷方法 3 */ 4 public class FileDemo3 { 5 public static void main(String[] args) throws IOException { 6 7 File file = new File("d:/1234.txt"); 8 //file.createNewFile(); 9 file.mkdir(); 10 //isDirectory 判斷是不是目錄(文件夾) 11 System.out.println(file.isDirectory()); 12 //isFile 判斷是不是文件 13 System.out.println(file.isFile()); 14 //isHidden 判斷是不是隱藏文件或文件夾 15 System.out.println(file.isHidden()); 16 //exists 判斷文件或者文件夾是否存在 17 System.out.println(file.exists()); 18 19 } 20 }
上述的方法是能夠根據指定的目錄(文件夾),獲取到這個目錄(文件夾)下的全部文件和文件夾數據。
String[] list() 它是獲取到指定文件夾下的全部文件和文件夾的名稱,將這些名稱保存到字符串數組中。
File[] listFiles() 它獲取到的是指定的文件夾下的全部文件和文件夾對象,並將這些對象存儲在File數組中。
1 /* 2 * 演示獲取指定目錄下的文件或文件夾名稱 3 */ 4 public class ListDemo { 5 public static void main(String[] args) { 6 7 //指定目錄 8 File dir = new File("d:/"); 9 10 //列出當前目錄下的文件和文件夾的名稱保存在字符串數組中 11 String[] list = dir.list(); 12 13 for (String s : list) { 14 System.out.println(s); 15 } 16 17 } 18 } 19 20 /* 21 * 獲取指定目錄下的文件和文件夾,會將這些文件和文件夾再次封裝成File對象 22 * 存儲在File數組中 23 */ 24 public class ListFilesDemo { 25 public static void main(String[] args) { 26 //建立File對象 27 File dir = new File("d:/"); 28 29 //列出指定目錄下的全部文件和文件夾對象 30 File[] files = dir.listFiles(); 31 32 for (File file : files) { 33 System.out.println(file.isDirectory()); 34 } 35 } 36 }
注意:使用list方法和listFiles方法獲取指定目錄下的文件和文件夾的時候,若是指定的目錄Java沒有權限,這時list或listFiles方法返回的結果是null。
1 /* 2 * 獲取指定目錄下,以及子目錄,子子目錄(多級目錄)下的全部內容 3 */ 4 public class ListFilesTest { 5 public static void main(String[] args) { 6 //獲取系統的全部盤符 7 File[] roots = File.listRoots(); 8 for(File root : roots){ 9 //列出每一個盤符下的全部文件 10 getFiles(root); 11 } 12 File dir = new File("d:/"); 13 getFiles(dir); 14 } 15 //獲取指定目錄下的文件和文件夾 16 public static void getFiles(File dir) { 17 System.out.println("......"+dir); 18 //列出當前這個目錄下的文件和文件夾對象 19 File[] files = dir.listFiles(); 20 if( files != null ){ 21 //遍歷數組 22 for (File file : files) { 23 //判斷當前的file是不是文件夾,是文件夾就須要繼續列出其中的文件或文件夾 24 if( file.isDirectory() ){ 25 //判斷成立說明當前的file對象必定是文件夾(目錄) 26 getFiles(file); 27 }else{ 28 //判斷不成立,說明當前的file對象必定是文件 29 System.out.println(file); 30 //file.delete(); 31 } 32 } 33 } 34 } 35 }