十四、泛型
集合的设计者不知道我们会用集合来保存什么类型的对象,所以他们把集合设计成能保存任何类型的对象,只要求具有很好的通用性,但这样做带来如下两个问题:
1、集合对元素类型没有任何限制,这样可能引发一些问题。例如,想创建一个只能保存 Dog 对象的集合,但程序也可以轻易地将 Cat 对象“丢”进去,所以可能引发异常。
2、由于把对象“丢进”集合时,集合丢失了对象的状态信息,集合只知道它盛装的是 Object,因此取出集合元素后通常还需要进行强制类型转换。这种强制类型转换既增加了编程的复杂度,也可能引发 ClassCastException 异常。
泛型可以在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高了代码的重用率。
主要用于反应我们不知道的类型和类型可有多种
package com.zpark.泛型;
public class Demo02YTest {
public static void main(String[] args) {
Demo02<Integer, Demo01<String>, String> d2 = new Demo02<>();
d2.setA(200);
d2.setB(new Demo01<>());
d2.setC("happy");
}
}
1、泛型集合
泛型本质上是提供类型的“类型参数”,也就是参数化类型。
我们可以为类、接口或方法指定一个类型参数,通过这个参数限制操作的数据类型,从而保证类型转换的绝对安全。
2、泛型类
除了可以定义泛型集合之外,还可以直接限定泛型类的类型参数。语法格式如下:
public class class_name<data_type1,data_type2,…>{}
3、泛型方法
定义泛型方法的语法格式如下:
[访问权限修饰符] [static] [final] <类型参数列表> 返回值类型 方法名([形式参数列表])
代码:
package com.zpark.泛型;
import java.util.ArrayList;
public class Demo04Test {
public static void main(String[] args) {
//创建Demo04对象
Demo04<ArrayList> d4 = new Demo04<>();
}
}
4、泛型的高级用法
限制泛型可用类型
使用类型通配符
继承泛型类和实现泛型接口
I/O 流
一、流的概念
流是一组有序的数据序列,将数据从一个地方带到另一个地方。由数据流的不同可分为输入(Input)流和输出(Output)流两种。
1、什么是输入/输出流
Java 程序所有的输入/输出以流的形式处理。
输入就是将数据从各种输入设备(包括文件、键盘等)中读取到内存中,
输出则正好相反,是将数据写入到各种输出设备(比如文件、显示器、磁盘等)。
例如 :键盘就是一个标准的输入设备,
显示器就是一个标准的输出设备,
但是文件既可以作为输入设备,又可以作为输出设备。
注意:输入和输出是针对与计算机内存而言的,不是用户本身
数据流是 Java 进行 I/O 操作的对象,它按照不同的标准可以分为不同的类别。
1、按照流的方向主要分为输入流和输出流两大类。
2、数据流按照数据单位的不同分为字节流和字符流。
3、按照功能可以划分为节点流和处理流。
数据流的处理只能按照数据序列的顺序来进行,即前一个数据处理完之后才能处理后一个数据。数据流以输入流的形式被程序获取,再以输出流的形式将数据输出到其它设备。
2、输入流
Java 流相关的类都封装在 java.io 包中,而且每个数据流都是一个对象。
所有输入流类都是 InputStream 抽象类(字节输入流)和 Reader 抽象类(字符输入流)的子类。其中 InputStream 类是字节输入流的抽象类,是所有字节输入流的父类
3、输出流
在 Java 中所有输出流类都是 OutputStream 抽象类(字节输出流)和 Writer 抽象类(字符输出流)的子类。其中 OutputStream 类是字节输出流的抽象类,是所有字节输出流的父类
二、系统流
每个 Java 程序运行时都带有一个系统流,系统流对应的类为 java.lang.System。Sytem 类封装了 Java 程序运行时的 3 个系统流,分别通过 in、out 和 err 变量来引用。这 3 个系统流如下所示:
System.in:标准输入流,默认设备是键盘。
System.out:标准输出流,默认设备是控制台。
System.err:标准错误流,默认设备是控制台。
三、字符编码介绍
计算机中,任何的文字都是以指定的编码方式存在的,在 Java 程序的开发中最常见的是 ISO8859-1、GBK/GB2312、Unicode、 UTF 编码。
Java 中常见编码说明如下:
ISO8859-1:属于单字节编码,最多只能表示 0~255 的字符范围。
GBK/GB2312:中文的国标编码,用来表示汉字,属于双字节编码。GBK 可以表示简体中文和繁体中文,而 GB2312 只能表示 简体中文。GBK 兼容 GB2312。
Unicode:是一种编码规范,是为解决全球字符通用编码而设计的。UTF-8 和 UTF-16 是这种规范的一种实现,此编码不兼容 I SO8859-1 编码。Java 内部采用此编码。
UTF:UTF 编码兼容了 ISO8859-1 编码,同时也可以用来表示所有的语言字符,不过 UTF 编码是不定长编码,每一个字符的长度为 1~6 个字节不等。一般在中文网页中使用此编码,可以节省空间。
在程序中如果处理不好字符编码,就有可能出现乱码问题。
本地的默认编码可以使用 System 类查看。Java 中 System 类可以取得与系统有关的信息,所以直接使用此类可以找到系统的默认编码。方法如下所示:public static Properties get
四、File类(文件操作类)
1、File类简介
在 Java 中,File 类是 java.io 包中唯一代表磁盘文件本身的对象.File 类定义了一些方法来操作文件,如新建、删除、重命名文件和目录等。
File 类不能访问文件内容本身,如果需要访问文件内容本身,则需要使用输入/输出流。
File类的构造方法:
File(String path):如果 path 是实际存在的路径,则该 File 对象表示的是目录;如果 path 是文件名,则该 File 对象表示的是文 件。
File(String path, String name):path 是路径名,name 是文件名。
File(File dir, String name):dir 是路径对象,name 是文件名。
文件的绝对路径是以磁盘开头,相对路径不以磁盘开头
f1.createNewFile()方法创建空文件
注意:删除目录时必须保证目录为空,否则删除失败
续表
package com.zpark.io.file;
import java.io.File;
import java.util.Arrays;
public class Demo01 {
public static void main(String[] args) {
/**
* File类常用方法
*/
File f1 = new File("C:/Users/燕一/Desktop/java");//./是当前包内
System.out.println(f1);
//测试应用程序是否能从指定的文件中进行读取
System.out.println(f1.canRead());//没有读的权限返回false
//测试是否能写当前文件
System.out.println(f1.canWrite());//当文件不能写时返回false
//测试当前File是否存在
boolean e1 = f1.exists();
System.out.println(e1);
//返回当前文件的绝对路径
System.out.println(f1.getAbsolutePath());
//返回当前对象的文件名或路径名
String n1 = f1.getName();
System.out.println(n1);
//返回当前File对象所对应目录的父目录
System.out.println(f1.getParent());
//测试当前file是否为绝对路径
boolean a1 = f1.isAbsolute();
System.out.println(a1);
//测试当前 File 对象表示的文件是否为一个路径
System.out.println(f1.isDirectory());
//测试当前 File 对象表示的文件是否为一个“普通”文件
boolean b1 = f1.isFile();
System.out.println(b1);
//返回当前 File 对象表示的文件最后修改的时间
System.out.println(f1.lastModified());
//返回当前 File 对象表示的文件长度
long l1 = f1.length();
System.out.println(l1);
//返回当前 File 对象表示的文件长度
String[] list1 = f1.list();
System.out.println(Arrays.toString(list1));
}
}
2、遍历与创建目录
package com.zpark.io.file;
import com.zpark.exception.Demo03;
import java.io.File;
public class Demo02 {
public static void main(String[] args) {
File f2 = new File("C:/Users/燕一/Desktop/java/PHP");
//创建一个目录,路径由当前File对象决定
boolean b2 = f2.mkdir();
System.out.println(b2);
//创建多个目录,路径由当前File对象决定
File f3 = new File("C:/Users/燕一/Desktop/java/DRY/WHI/ZF");
System.out.println(f3.mkdirs());
//将当前File对象指定的文件更名为参数File指定的路径名
File f4 = new File("C:/Users/燕一/Desktop/java/Demo01.txt");
boolean b = f4.renameTo(new File("C:/Users/燕一/Desktop/java/LXF.txt"));
System.out.println(b);
//遍历目录
File f5 = new File("C:/");
System.out.println("文件名称\t\t文件类型\t\t文件大小\t");
System.out.println("------------------------------------------");
String[] list = f5.list();
for (int i = 0; i < list.length; i++) {
System.out.print(list[i] + "\t\t");
System.out.print((new File("C:/",list[i])).isFile()?"文件" + "\t\t" : "文件夹" + "\t\t");
System.out.println((new File("C:/",list[i])).length() + "字节");
}
}
}
File 类中有以下两个常用常量:
public static final String pathSeparator:指的是分隔连续多个路径字符串的分隔符,Windows 下指;。例如 java -cp test.jar;abc.jar HelloWorld。
public static final String separator:用来分隔同一个路径字符串中的目录的,Windows 下指/。例如 C:/Program Files/Common Files。
五、RandomAccessFile类
1、动态读取文件内容
RandomAccessFile 是 Java 输入/输出流体系中功能最丰富的文件内容访问类,它提供了众多的方法来访问文件内容,它既可以读取文件内容,也可以向文件输出数据。由于 RandomAccessFile 可以从任意位置访问文件,所以在只需要访问文件部分内容的情况下,使用 RandonAccessFile 类是一个很好的选择。
RandomAccessFile类提供了两个构造方法:
RandomAccessFile(File file, String mode)
其中file表示文件对象,mode表示文档的属性(常用属性有r:只读模式,w:只写模式,rw:可读可写模式)
RandomAccessFile(String path, String mode)
其中path表示文件对象,mode表示文档的属性(常用属性有r:只读模式,w:只写模式,rw:可读可写模式)
注意:当指定路径下文件不存在则会创建该文件对象
RandomAccessFile 类中提供了一些常用读取和写入数据的方法
写入数据
注意:在写入内容时,每写一次会清空原本的内容
UTF-8一个中文占3个字节
读取数据
read();//每次读取一个字节
readLine
public static void main(String[] args) throws Exception {
File f = new File(“dir/a_name.txt”);
RandomAccessFile raf1 = new RandomAccessFile(f,“r”);
//int read = raf1.read();每次只能读一个字节
//System.out.println(read);
//System.out.println(raf1.readLine());
//获取文件长度
long l = raf1.length();
byte[] data = new byte[(int)l];
raf1.read(data);
//将二进制转换为中文
String str = new String(data);
System.out.println(str);
//关闭文件
raf1.close();
}
六、字节流的使用
1、字节输入流
InputStream类的子类
ByteArrayInputStream 类:将字节数组转换为字节输入流,从中读取字节。
FileInputStream 类:从文件中读取数据。
PipedInputStream 类:连接到一个 PipedOutputStream(管道输出流)。
SequenceInputStream 类:将多个字节输入流串联成一个字节输入流。
ObjectInputStream 类:将对象反序列化。
文件指针:
当读取到文件末尾时返回-1
FileInputStream: 文件字节输入流
FileInputStream: 从文件系统中从文件系统中的文件获取输入字节。 什么文件可用取决于主机环境。
FileInputStream: 用于读取诸如图像数据的原始字节流。
构造方法:
FileInputStream(File file) 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
FileInputStream(FileDescriptor fdObj) 通过使用文件描述符 fdObj创建 FileInputStream ,该文件描述符表示与文件系统中的实际文件的现有连接。
FileInputStream(String name) 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。
2、字节输出流
OutputStream类的子类
ByteArrayOutputStream 类:向内存缓冲区的字节数组中写数据。
FileOutputStream 类:向文件中写数据。
PipedOutputStream 类:连接到一个 PipedlntputStream(管道输入流)。
ObjectOutputStream 类:将对象序列化。
文件输出流是用于将数据写入File或FileDescriptor的输出流。
文件是否可用或可能被创建取决于底层平台。
特别是某些平台允许一次只能打开一个文件来写入一个FileOutputStream (或其他文件写入对象)。 在这种情况下,如果所涉及的文件已经打开,则此类中的构造函数将失败。
FileOutputStream用于写入诸如图像数据的原始字节流。
构造方法:
FileOutputStream(File file) 创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(FileDescriptor fdObj) 创建文件输出流以写入指定的文件描述符,表示与文件系统中实际文件的现有连接。
FileOutputStream(File file, boolean append) 创建文件输出流以写入由指定的 File对象表示的文件。
参数 :
file - 要打开的文件进行写入。
append - 如果是 true ,则字节将写入文件的末尾而不是开头
FileOutputStream(String name) 创建文件输出流以指定的名称写入文件。
FileOutputStream(String name, boolean append) 创建文件输出流以指定的名称写入文件。
3、字节数组输入流
ByteArrayInputStream 类可以从内存的字节数组中读取数据,该类有如下两种构造方法重载形式。
1、ByteArrayInputStream(byte[] buf):创建一个字节数组输入流,字节数组类型的数据源由参数 buf 指定。
2、ByteArrayInputStream(byte[] buf,int offse,int length):创建一个字节数组输入流,其中,参数 buf 指定字节数组类型的数据源,offset 指定在数组中开始读取数据的起始下标位置,length 指定读取的元素个数。
七、字符流的使用(高级流)
1、字符输入流
Reader 类是所有字符流输入类的父类,它常用的子类有:
CharArrayReader 类:将字符数组转换为字符输入流,从中读取字符。
StringReader 类:将字符串转换为字符输入流,从中读取字符。
BufferedReader 类:为其他字符输入流提供读缓冲区。
PipedReader 类:连接到一个 PipedWriter。
InputStreamReader 类:将字节输入流转换为字符输入流,可以指定字符编码。
2、字符输出流
Writer 类是所有字符输出流的父类,它常用的子类
CharArrayWriter 类:向内存缓冲区的字符数组写数据。
StringWriter 类:向内存缓冲区的字符串(StringBuffer)写数据。
BufferedWriter 类:为其他字符输出流提供写缓冲区。
PipedWriter 类:连接到一个 PipedReader。
注意:先关字节流,再关字符流
3、字符文件输入流
构造方法:
(1)、FileReader(File file):在给定要读取数据的文件的情况下创建一个新的 FileReader 对象。其中,file 表示要从中读取数据的文件。
(2)、FileReader(String fileName):在给定从中读取数据的文件名的情况下创建一个新 FileReader 对象。其中,fileName 表示要从中读取数据的文件的名称,表示的是一个文件的完整路径。
在用该类的构造方法创建 FileReader 读取对象时,默认的字符编码及字节缓冲区大小都是由系统设定的。需要自己指定这些值,可以在 FilelnputStream 上构造一个 InputStreamReader。
注意:在创建 FileReader 对象时可能会引发一个 FileNotFoundException 异常,因此需要使用 try catch 语句捕获该异常
4、字符文件输出流
构造方法:
(1)、FileWriter(File file):在指定 File 对象的情况下构造一个 FileWriter 对象。其中,file 表示要写入数据的 File 对象。
(2)、FileWriter(File file,boolean append):在指定 File 对象的情况下构造一个 FileWriter 对象,如果 append 的值为 true,则将字节写入文件末尾,而不是写入文件开始处。
(3)、FileWriter(String fileName):在指定文件名的情况下构造一个 FileWriter 对象。其中,fileName 表示要写入字符的文件名,表示的是完整路径。
(4)、FileWriter(String fileName,boolean append):在指定文件名以及要写入文件的位置的情况下构造 FileWriter 对象。其中,append 是一个 boolean 值,如果为 true,则将数据写入文件末尾,而不是文件开始处。
在创建 FileWriter 对象时,默认字符编码和默认字节缓冲区大小都是由系统设定的。要自己指定这些值,可以在 FileOutputStream 上构造一个 OutputStreamWriter 对象。
注意:在创建 FileWriter 对象时可能会引发 IOException 或 SecurityException 异常,因此需要使用 try catch 语句捕获该异常。
5、字符缓冲区输入流
BufferedReader 类主要用于辅助其他字符输入流,它带有缓冲区,可以先将一批数据读到内存缓冲区。
接下来的读操作就可以直接从缓冲区中获取数据,而不需要每次都从数据源读取数据并进行字符编码转换,
这样就可以提高数据的读取效率。
构造方法:
(1)、BufferedReader(Reader in):创建一个 BufferedReader 来修饰参数 in 指定的字符输入流。
(2)、BufferedReader(Reader in,int size):创建一个 BufferedReader 来修饰参数 in 指定的字符输入流,参数 size 则用于指定缓冲区的大小,单位为字符。
6、字符缓冲区输出流
BufferedWriter 类主要用于辅助其他字符输出流,它同样带有缓冲区,可以先将一批数据写入缓冲区,
当缓冲区满了以后,再将缓冲区的数据一次性写到字符输出流,其目的是为了提高数据的写效率。
构造方法:
(1)、BufferedWriter(Writer out):创建一个 BufferedWriter 来修饰参数 out 指定的字符输出流。
(2)、BufferedWriter(Writer out,int size):创建一个 BufferedWriter 来修饰参数 out 指定的字符输出流,参数 size 则用于指定缓冲区的大小,单位为字符。
注意:BufferedWriter 类的使用与 FileWriter 类相同。
八、转换流
1、InputStreamReader 用于将字节输入流转换为字符输入流,是高级流(字符流)
InputStreamReader是从字节流到字符流的桥梁:它读取字节,并使用指定的charset将其解码为字符。
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
每个调用InputStreamReader的read()方法之一可能会导致从底层字节输入流读取一个或多个字节。
为了使字节有效地转换为字符,可以从底层流读取比满足当前读取操作所需的更多字节。
2、OutputStreamWriter 用于将字节输出流转换为字符输出流。字符流(高级流)
作用:专用于与文本的读写
对应的构造方法:
OutputStreamWriter(OutputStream out) 该构造方法会使用相同默认的字符编码
OutputStreamWriter(OutputStream out, String charsetName) 该构造方法可以指定字符集
OutputStreamWriter是从字符流到字节流的桥梁:使用指定的charset将写入的字符编码为字节。
它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
每次调用write()方法都会使编码转换器在给定的字符上被调用。 所得到的字节在写入底层输出流之前累
积在缓冲区中。 请注意,传递给write()方法的字符不会缓冲。
为了最大的效率,请考虑在BufferedWriter中包装一个OutputStreamWriter,以避免频繁的转换器调用。
作用:使用转换流可以在一定程度上避免乱码,还可以指定输入输出所使用的字符集。
————————————————