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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值