Java 高階-類_集合類,IO流

列表,集合,Map只能存儲引用類型,數組可以存儲引用類型和基本類型。
列表類:ArrayList:
實現所有可選列表操作,並允許所有元素,包括null(add(null)與remove(null)不限執行次數) 。
創建:
ArrayList list = new ArrayList(); 判空:list.isEmpty();
添加:
list.add(Object object);
list.addAll(Collection col);【添加一個集合對象】 長度:list.size();
插入:
list.add(index x,Object object);
list.addAll(index,Collection col); 判存:list.contains(元素值,如"makle");
取值:
list.get(index x); ArrayList中元素類型默認是Object類型
移除:
list.remove(index x); list.remove(list中的元素);
遍歷:
1、for循環 ; 2、Iterator(遍歷器)【Iterator iterator = list.iterator();
while(iterator.hasNext())
iterator.next();
】 ; 3、增強版的for循環 :for(Object o: list):{}
4、轉換爲數組:Object[] o = list.toArray(); 再遍歷

列表類:Vector:
用法與ArrayList基本相同,但Vector線程安全,ArrayList線程不安全。

列表類:LinkedList:
用法與ArrayList基本相同,不同點:
LinkedList採用引用存儲,插入和刪除更快,多了addFirst()和addLast()方法;
ArrayList採用數組存儲。

泛型:通過<>來指定列表,集合裏面的類型
可以對使用泛型,來明確存儲的類型,後續使用時不用強制類型轉換:

ArrayList<Integer> al =new ArrayList<Integer>();
Vector<String> ve = new Vector<String>();
LinkedList<Character> ll = new LinkedList<Character>();
再次使用for循環取出元素時,可直接取出對應類型(而不是默認的Object類型)。

集合類:HashSet:
ArrayList,LinkedList,Vector可以存儲重複的元素,是有序的(按添加的順序);
HashSet 存儲的元素不重複,是無序的(按照內部算法進行排序)。
由於無序,所以HashSet沒有get方法。

集合類:TreeSet
與HashSet的不同:
HashSet:內部的數據結構是哈希表,是線程不安全的。
HashSet中保證集合中元素是唯一的方法:通過對象的hashCode和equals方法來完成對象唯一性的判斷:

如果對象的hashCode值不同,則不用判斷equals方法,就直接存到HashSet中。
如果對象的hashCode值相同,需要用equals方法進行比較,
如果結果爲true,則視爲相同元素,不存,
如果結果爲false,視爲不同元素,進行存儲。

注意:如果元素要存儲到HashCode中,必須覆蓋hashCode方法和equals方法。

TreeSet:可以對Set集合中的元素進行排序(不一定爲add順序),是線程不安全的。
TreeSet中判斷元素唯一性的方法是:根據比較方法的返回結果是否爲0,

如果是0,則是相同元素,不存,
如果不是0,則是不同元素,存儲。

TreeSet對元素進行排序的方式:

元素自身具備比較功能,即自然排序,需要實現Comparable接口,並覆蓋其compareTo方法。
元素自身不具備比較功能,則需要實現Comparator接口,並覆蓋其compare方法。

Map:HashMap:
是鍵值對的集合,無序(根據內部排序方式進行排序)
key不能相同,相同時新的value會覆蓋舊的value
常用的方法:
put:放入鍵值對
get:根據key取對應的value
keySet:返回一個包含所有key的Set
values:返回一個包含所有value的Set(順序與keySet返回的Set中的順序一致)
containskey:判斷是否包含key

Map:TreeMap:
與HashMap的用法基本相同,不同點:
TreeMap內部樹型存儲,HashMap內部哈希存儲。
Map:Hashtable:
與HashMap的用法基本相同,不同點:
Hashtable線程安全,HashMap線程不安全

泛型的使用:
創建並使用含泛型的列表類:

public class MyArrayList<T>{

private T[] array = (T[]) new Object[100];
private int index = 0;

	public void add(T x) {
	if(index < 100)
		array[index] = x;
	index++;
	}

	public T get(int index) {
	if(index>=0&&index<this.index)
		return array[index];
	else
		return null;
	}

	public int size() {
	return index;
	}
}

使用:

public static void main(String[] args) {
	MyArrayList<String> as =new MyArrayList<String>();
	
	as.add("siki");
	as.add("want");
	
	for(int i=0;i<as.size();i++)
          System.out.print(as.get(i)+" ");
	
	MyArrayList<Integer> al =new MyArrayList<Integer>();
	
	al.add(123);
	al.add(456);
	
	for(int i=0;i<al.size();i++)
          System.out.print(al.get(i)+" ");

}

可變參數:
指參數的個數可以改變:

public static void main(String[] args) {
System.out.println(add(5));
System.out.println(add(5,6,7));
System.out.println(add(1,2));
}
public static int add(int... args) {
//可以傳遞任意數量的int類型參數,args用法相當於一個數組,args名字任意
int result = 0;
for(int i:args)
	result+=i;
return result;
}

1、可變是指個數可變,且個數可爲0
2、在調用方法時,若對固定參數與含可變參數的方法都能匹配,則優先匹配固定參數的方法。
3、一個方法最多隻能有一個可變參數,且可變參數必須是最後一個參數的位置。

使用Junit:
1、引入Junit的jar包:
在eclipse中,右鍵某一項目–>Build Path,Configure Build Path---->在Java Build Path 下選擇Libraries,Add Library…—>Junit,Next,Junit5(最新版本)---->Finish
2、使用Junit進行單元測試:
【對某非static的方法使用註解@Test即可進行單元測試!】
在這裏插入圖片描述
在該程序中,右鍵選擇Run As,Junit Test,即可完成對print()的單元測試。

查看類的源碼:
在eclipse中Ctrl+左鍵點擊某個類或方法,即可查看該模塊的源碼。
在安裝的jdk文件中的lib,src.zip中包含着各類的源碼。

轉義字符:
一些簡單的轉義字符:https://blog.csdn.net/twc18638942853/article/details/56830881

IO流:

由.listFiles()獲得的File順序爲:先文件默認升序,再文件夾默認升序。
由.list()獲得的File的name順序與 .listFiles()獲得的File順序一致。

File對象的創建:

指向一個文件夾:
File p1 = new File("D:\\Test");
File p2 = new File("D:\\Test","Test2");
File p3 = new File(p1,"Test2");
指向一個文件:
File f1 = new File("D:\\Test\\demo1.txt");
File f2 = new File("D:\\Test","demo1.txt");
File f3 = new File(p1,"demo1.txt");

常用判斷方法:

//判斷是否是文件夾
System.out.println(p1.isDirectory());//true
System.out.println(f1.isDirectory());//false
System.out.println("----------------------");
//判斷是否是文件
System.out.println(p1.isFile());//false
System.out.println(f1.isFile());//true
System.out.println("----------------------");
//判斷是否存在
System.out.println(p1.exists());
System.out.println(f1.exists());
System.out.println("----------------------");
//判斷是否可讀
System.out.println(p1.canRead());
System.out.println(f1.canRead());
System.out.println("----------------------");
//判斷是否可寫
System.out.println(p1.canWrite());
System.out.println(f1.canWrite());
System.out.println("----------------------");
//判斷是否隱藏
System.out.println(p1.isHidden());
System.out.println(f1.isHidden());
System.out.println("----------------------");

刪除,創建和重命名:

//創建新的文件,若文件已存在則創建失敗
	System.out.println(f1.createNewFile());
//只能創建一級文件夾,已存在返回false
	System.out.println(p1.mkdir());
//可以創建多級文件夾,已存在返回false
	System.out.println(p1.mkdirs());
//當delete對象是文件夾時,爲空文件夾纔可刪除成功
	System.out.println(p1.delete());
	System.out.println(f1.delete());
//改名的參數需是一個File對象,.renameTo()也有移動+重命名的作用
	System.out.println(p1.renameTo(new File("d:/test")));
	System.out.println(f1.renameTo(new File("d:/test/demo2.txt")));

獲取路徑方法:

File f2 = new File("test/test");
System.out.println(f2.mkdirs());
//獲取文件f2的絕對路徑
	System.out.println(f2.getAbsolutePath());//F:\備份\eclipse 4.12\chapter3\followCourse\test\test
//獲取文件f2在定義時的路徑
	System.out.println(f2.getPath());//test\test

獲取name,length,最後修改時間:

File p1 = new File("d://test/Test2");
	File f1 = new File("d:/test/demo2.txt");
	
	//獲取name
	System.out.println(p1.getName());
	System.out.println(f1.getName());
	//獲取父目錄name
	System.out.println(p1.getParent());
	System.out.println(f1.getParent());
	//獲取文本文件大小(字節)
	System.out.println(p1.length());
	System.out.println(f1.length());
	//獲取文件夾(名稱),文件的最後修改時間(毫秒)
	System.out.println(p1.lastModified());
	System.out.println(f1.lastModified());
	System.out.println("----------------");
	System.out.println(new Date(p1.lastModified()).toString());
	System.out.println(new Date(f1.lastModified()).toString());

在這裏插入圖片描述
獲取目錄下的內容:

File p1 = new File("d://test");
	
	//獲取文件夾下包含的文件和文件夾name的列表
	String[] strs = p1.list();
	for(String s:strs)
	{
		File f = new File(p1,s);
		System.out.print(f.getPath()+" ");
		System.out.print(s+" ");
	}
	System.out.println();
	
	//獲取文件夾下的File列表
	File[] fls = p1.listFiles();
	for(File f:fls) {
		System.out.print(f.getAbsolutePath()+" ");
		System.out.print(f.getName()+" ");
	}
	System.out.println();      //上下兩個模塊的print結果一樣

剪切:
可以使用File的.renameTo()完成剪切。
複製:
使用Files的.copy(sourceFile.toPath(),outFile.toPath())完成複製,
outFile的最終目標文件或文件夾不存在會先自動創建。但其父目錄必須全部已存在!
可以使用exists()與mkdirs()進行創建

複製的文件夾【爲空文件夾,複製爲xx.txt 則文件夾名爲xx.txt】
複製的.txt文件【包含原.txt文件內容,複製爲name不帶後綴則文件無特定擴展名】

IO流 Input與Output:
將數據由硬盤讀取到內存中->讀入read–>輸入–>Input–>輸入流
將數據從內存保存到硬盤–>存儲–>寫入write–>Output—>輸出流

計算機中的數據都是二進制存儲的,但這裏我們將可以用notepad打開並可直接識別的數據稱爲文本數據,其他都稱爲二進制(字節)數據

數據流:
字節流:可以讀取任意類型的數據
            抽象基類:InputStream ,OutputStream
字符流:只可讀取文本數據
            抽象基類:Reader , Writer

文件輸入流的簡單使用:
FileInputStream【通常採用字節數組讀取】

FileInputStream fis = null; //使輸入流fis在finally中可以訪問
	
	try {
		 fis = new FileInputStream("test/text");
		
		 int m;//按照單個字節讀取
		 //每使用一次read(),指針都會後移一位,沒有指向內容時返回-1
		 while((m = fis.read())!=-1)
			 System.out.print((char)m);
		 //中文會輸出亂碼,因爲中文不止佔一個字節
		 
		 System.out.println();
		 
		 fis = new FileInputStream("test/text");
		 byte[] ch = new byte[4];//按照字節數組讀取,較單字節讀取速度更快
		 //數組參數不易過大,否則開闢內存過大
		 while((m = fis.read(ch)) != -1) {
			 //讀取到byte數組中的此次內容會替換上次的內容,
			 //未讀取到新內容的位置不進行替換,所以控制String的長度
			 System.out.print(new String(ch,0,m));
		 }
		 
		
	} catch (IOException e) {
		
		e.printStackTrace();
	}finally //無論上述代碼是否出現異常都要對流進行終止
	{
	try {
		if(fis!=null)
			fis.close();//若流創建成功且使用結束則在此關閉輸入流
	} catch (IOException e) {
		
		e.printStackTrace();
	}
	}

文件輸出流:
FileOutputStream:【常用按照byte數組寫入】
文本文件的write對象可以不存在,不存在的情況下會先創建該文件再進行寫入。
每次寫入都會把文件對象的原內容覆蓋

FileOutputStream fos = null;
	try {
		//FileOutputStream的構造方法無第二個參數時默認每次清空重寫
		//使用第二個參數爲true時採用追加寫入
		fos = new FileOutputStream("test/text2",true);
		
		//單個字節寫入
		fos.write('h');
		fos.write('e');fos.write('l');fos.write('l');fos.write('o');
		
		//字符數組寫入,默認即可寫入中文
		String s = "我愛你祖國aabb!";
		//寫入byte數組(,起始位置,長度)
		fos.write(s.getBytes());

	} catch (IOException e) {	
		e.printStackTrace();
	}
	finally {
	try {
		if(fos!=null)
		fos.close();
	} catch (IOException e) {
		e.printStackTrace();
	}
	}//finally

使用FileInputStream和FileOutputStream可以實現對文本文件或
非文本文件的複製:

@Test
public void copyTest() {
long start,end;
//返回的單位是毫秒,與系統當前時間有關
start = System.currentTimeMillis();
copy("test/1.jpg","test/2.jpg");
end = System.currentTimeMillis();
}

public static void copy(String source,String target) {
	FileInputStream fls = null;
	FileOutputStream fos = null;

try {
	fls = new FileInputStream(source);
	fos = new FileOutputStream(target);

	//使用單個byte複製
	int m = -1;
//	while((m = fls.read())!=-1)
//	fos.write(m);
	
	//使用byte數組複製可極大地提高效率
	byte[] b =new byte[2048];
	while((m = fls.read(b))!=-1)
		fos.write(b,0,m);


} catch (IOException e) {
	
	e.printStackTrace();
}finally {
	//在不同try模塊中分別關閉,防止前一個close失敗使後一個無法成功close
	try {
		if(fls!=null)
		fls.close();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	try {
		if(fos!=null)
		fos.close();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}}

緩衝區輸出流:BufferedOutputStream:
又稱包裝流–>構造時:
BOS = new BufferedOutputStream(new FileOutputStream("")【,size】);
只在下面三種情況發生時,完成一次緩衝區到硬盤的寫入:
1、(size)緩衝區滿了 2、調用BOS的flush(); 3、調用BOS的close();
緩衝器區輸入流:BufferedInputStream:
與BufferedOutputStream相似

//第一次read從硬盤讀默認大小的緩衝區的數據並將此數據從緩衝區讀到m
//後來每次read都是從緩衝區中取值,知道緩衝區被取空
//其中bis爲BufferedInputStream對象,使用默認緩衝區大小
int m; 
m = bis.read();
System.out.println((char)m);
m = bis.read();
System.out.println((char)m);

//每次從緩衝區最多讀1024個字節
byte[] b = new byte[1024];
m = bis.read(b);
System.out.println(new String(b,0,m));

使用緩衝區輸入輸出流採用字節數組進行搬運,所得的效率最高

編碼格式:
不同的編碼格式對應不同的編碼表【包含字符與其所對應的二進制數據,計算機存儲二進制數據,再根據編碼格式找到對應的字符,當找不到時,返回?】。

字符輸入輸出流:
InputStreamReader,OutputStreamWriter

用法與BufferedInputStream和BufferedOutputStream相似,
都需包裝一個文件輸入輸出流
且其內置了緩衝區,在不滿足3個條件之一時不將緩衝區內容寫入。
可以在構造方法調用時規定寫入和讀取的編碼格式,只有兩端的編碼格式相同時,可以保證不亂碼,默認採用平臺的編碼格式。

FileReader,FileWriter:
兩個類分別繼承自InputStreamReader,OutputStreamWriter,優化了父類的構造方法,可以直接給一個File路徑作爲參數,不能設置字符集,改爲是否採用append模式的確認。
方法直接繼承父類。
使用字符輸入輸出流只能完成文本文件的複製。

字符的緩衝區輸入輸出流:
BufferedReader,BufferedWriter包裝FileReader和FileWriter,
構造參數可顯式設置緩衝區大小,其中BufferedReader 獨有方法readLine() 可以按行讀取。
【字符輸入流read()一次返回讀取到的字符對應的int值,輸出原字符需(char)強制,
字符輸出流write(int/char)一次寫入的都是(char)強制後的字符,寫入原數字需使用write(“12”)形式】

關於上述IO流的總結:(每層縮進代表繼承)
字節流:
InputStream
FileInputStream
BufferedInputStream(包裝流,包裝字節流)
OutputStream
FileOutputStream
BufferedOutputStream
字符流:
Reader
InputStreamReader(包裝流,包裝字節流)
FileReader
BufferedReader(包裝流,包裝字符流)
Writer
OutputStreamWriter
FileWriter
BufferedWriter

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章