【无标题】

第四周笔记

一、 异常

1. 什么是异常

程序运行是,发生的不被期望的事件,它组织了程序按照程序员的预期正常执行,这就是异常

常见的异常

  • 算术异常:ArithmeticException
  • 空指针异常:NullPointerException
  • 数组下标越界异常:ArrayIndexOutOfBoundsException
  • 类型转换异常:ClassCastException
  • 数组负下标异常:NegativeArrayException
  • 字符串转换为数字异常:NumberFormatException
  • 输入类型不匹配:inputMisMatchException

2. 异常处理

2.1 什么是异常处理

异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。

异常处理机制:捕获异常抛出异常

捕获异常: try、catch、finally

抛出异常: throw、throws

2.2 异常处理

Java标准库内建了一些通用的异常,这些类以Throwable为顶层父类。Throwable又派生出Error类和Exception类。

错误:Error类以及他的子类的实例,代表了JVM本身的错误。错误不能被程序员通过代码处理,Error很少出现。

异常:Exception以及他的子类,代表程序运行时发送的各种不期望发生的事件。可以被Java异常处理机制使用,是异常处理的核心。

Exception异常分为两类运行时异常编译异常

  1. 运行时异常(不受检异常):RuntimeException类极其子类表示JVM在运行期间可能出现的错误。比如说试图使用空值对象的引用(NullPointerException)、数组下标越界(ArrayIndexOutBoundException)。此类异常属于不可查异常,一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。
  2. 编译时异常(受检异常):Exception中除RuntimeException极其子类之外的异常。如果程序中出现此类异常,必须对该异常进行处理,否则编译不通过。在程序中,通常不会自定义该类异常,而是直接使用系统提供的异常类。

3. 异常关键字

Java的异常处理是通过5个关键字来实现的

try、catch、finally 捕获异常

throw、throws 抛出异常

Final和Finally区别

  • final 可以用来修饰变量——常量,这个值是一个最终的了,不能被修改了
    • 修饰方法 —— 这个方法是最终的方法了,不能被重写了
    • 修饰类 —— 这个类是一个最终的类,不能被继承
  • finally是异常组合的一个代码块,表示的是一段一定会被执行的代码
  • final和finally没有直接关系

Finally和return的执行顺序

  • 不管有没有出现异常,finally块中的代码都会执行
  • 当try-catch中有return时,finally仍然会执行
  • finally是在return语句执行之后,返回之前执行的(此时并没有返回运算的值,而是先把要返回的值保存起来,不管finally中的代码增么样,返回的值都不会改变,仍然是之前保存的值),所以函数返回值是在finally执行之前就已经确定了的
  • finally中如果包含return,那么程序将在这里返回,而不是try或catch中的return返回,返回值就不是try或catch中保存的返回值了

注意

Finally唯一不被执行的情况:当发生异常事件,在程序中手动的退出系统:System.exit(1);

4. 捕获异常

4.1 try-catch-finally语句
try {
    //监控区,有可能出现异常的代码
    //如果程序没有异常,则忽略catch
    //如果出现了异常,异常后面的代码都不会执行
    //立即到catch块中来进行匹配(catch解决异常的,一个catch解决一个异常,可以多个)
    //如果没有匹配的catch块,则程序报错
    //如果有匹配的异常类型,则会进行catch中,只要进去了,则认为异常被解决了,后面的代码还会执行
    //注意:多个catch,异常类型是从小到大完成的。
}catch(异常类型 e) {
    
}finally{
    //最终的:不管程序是不是发送了异常,这里的代码一定会执行
    //一般会做资源的释放
}

捕获总结

  • try 代码块:用于捕获异常。其后可以接零个或者多个catch块。如果没有catch块,后必须跟finally块,来完成资源释放等操作
  • catch 代码块:用于捕获异常,并在处理异常
  • finally 代码块:无论是否捕获异常,finally代码总会被执行。如果try代码块或者catch代码块中有return语句时,finally代码块将在方法返回前被执行。唯一一种finally不会被执行的情况就是发送异常时,手动的退出系统。

5. 抛出异常

如果一个方法可能会出现异常,但没有能力处理这种异常,或者自己不想解决的话,可以将异常抛出。

5.1 throws抛出异常
public  void  methodName() throws Exception1,Exception2.{
}

如果一个方法向外抛出了异常,那异常由谁来解决?

  1. 调用者,谁调用这个方法就由谁来解决
  2. 如果调用者也解决不了呢?调用者可以继续向外抛出这个异常
5.2 throw 抛出异常
throw new ExceptionType;
try{
//可能会发生异常的代码
}catch(Exception e){
   throw new Exception(e);
}
5.3 throw与throws
throwthrows
生成并抛出异常声明方法内抛出了异常
位于方法体内部,可作为单独语句使用必须跟在方法参数列表后面,不能单独使用
抛出一个异常对象,且只能是一个声明抛出异常类型,可以跟多个异常

6. 自定义异常

class  <自定义异常名>  extends  <Exception>

自定义异常的具体步骤

  1. 定义一个类继承Exception或者其子类
  2. 编写构造方法(无参和有参)
  3. 在需要的地方调用异常类(使用throw抛出实例化后的异常)—— 在方法的声明中需要声明

7. 异常使用原则

从性能角度看

  1. 不要将所有的代码都放在try中,try只放有可能发送异常的代码
  2. 在catch中指定具体的异常类型

能解决的使用捕获,不能解决的使用抛出

二、 集合

1. 集合框架介绍

在这里插入图片描述

2. Collection介绍

Collection位于java.util包下。

Collection接口是集合体系的顶层接口,它是用来定义集合的最基本的操作行为的。

Collection集合中可以存放多个对象,其中存放的对象称为元素。

Collection直接的子接口ListSet

迭代器

要遍历集合,首先要做事情先判断集合中有没有元素,有元素就把当前这个元素取出来,然后再判断有没有,如果还有继续取出。直到把所有元素全部取出。Iterator接口定义了三个方法:迭代器

  • hasNext() 问集合中有没有下一个元素; 调用这个方法会返回一个boolean类型的值,如果有则返回true, 没有返回false
  • next() 取出当前这个元素;, 取值
  • remove() 删除当前的元素

3. List集合

List接口继承了Collectoin接口,List接口就拿到Collection接口中的所有方法,同时List接口根据自己的特点,还定义了额外,主要是围绕List的下标而设计的特有功能。

List它描述的所有有序集合的公共行为。并且List接口描述的集合它拥有下标(索引index),我们就可以根据这个下标来操作集合中的元素。List接口描述的集合中允许存放重复元素

List集合存储元素的特点有序、可重复

List接口的实现类:ArrayList、LinkedList

ArrayList实现了长度可变的数组,在内存中分配连续的空间,遍历元素和随机访问元素的效率比较高 - 查询比较快

LinkedList采用链表存储方式,插入、删除元素时效率比较高

3.1 ArrayList

ArrayList集合的特点:底层使用可变数组 储存的元素:有序、可重复

不足:查询快,删除慢

常用方法

  • 增加

    • boolean add( Object element ) 把当前的element元素添加集合的尾部,成功返回true, 失败返回false;
    • void add(int index, E element) 在集合中指定位置上添加元素
    • **注意:**使用add方法添加元素的时候,一定要保证指定的位置前面有元素。否则会发生下标越界异常。
  • 删除

    • remove(Object obj) 删除集合中指定的元素,移除第一次出现的元素,没有不会报错
    • Object remove(int index) 删除集合中指定位置上的元素,并返回被删除的元素 。删除时指定的下标的位置一定要保证有元素。
    • clear() 清空集合中所有元素,会让集合中的size变成0。
    • 注意:使用List调用remove如果指定的是值,这时这个值一定是下标(默认),因此如果要删除集合中存放的包装类型的数据,这时需要把这个int值包装成对应的Integer类型,Integer.valueOf(int)。
  • 修改

    • Object set(int index, E element) 修改集合中指定位置上的数据。原来的元素就被删除掉了。返回被替换的那个元素。
  • 查询

    • get(int index) 返回此列表中指定位置上的元素
  • 常用

    • size() 求一个集合的长度
    • isEmpty(), 判断这个集合是不是空的,如果为空集合返回true,否则为false
    • boolean contains(Object o) ,判断列表中是否存在指定元素
  • 遍历

    • For

    • Foreach

    • Iterator

      • 获取迭代器对象

      • 用while循环遍历

      • Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            Object o = iterator.next();
            System.out.println (o);
        }
        
3.2 LinkedList

底层采用的链接列表(链表),由于链表有头和有尾的数据结构,因此LinkedList集合中定义了自己的特有方法,这些方法都围绕链表的头和尾设计的。新增、删除元素时,效率比较高。

方法名说明
void addFirst(Object o)在列表的首部添加元素
void addLast(Object o)在列表的末尾添加元素
Object getFirst()返回列表中的第一个元素
Object getLast()返回列表中的最后一个元素
Object removeFirst()删除并返回列表中的第一个元素
Object removeLast()删除并返回列表中的最后一个元素
3.3 ArrayList和LinkedList比较
  1. 二者都是List接口的实现类,存储的元素都是有序可重复的
  2. ArrayList底层维护的是可变数组来存放元素,查询快,增删慢
  3. LinkedList底层采用的是链表结构增删快,查询慢
  4. LinkedList比ArrayList多了头尾元素的操作方法

4. Set集合

Set接口描述的是一种比较简单的一种集合,集合中的对象并不按特定的方式排序,并且不能保存重复的对象

HashSet是Set接口的常用实现类。而Set接口继承了Collection接口,同时没有添加新的方法,所以在使用上与List接口的实现类使用方式一致。都是有增加元素的add方法和获取元素个数的size方法。

Set集合存储数据的特点:无序,不可重复

调用set集合添加方法的时候,最终底层在调用object类中的hashCode() - 计算一个对象的hash值的,最终就是一串数字

在Set集合中是不存在下标的,也没有get方法,无法一个一个取值,无法用for循环遍历,只能使用foreach或者迭代器

HashSet集合如何保证元素不重复?

  • 当给Hashset中存放元素的时候会先调用对象的hashCode方法,计算哈希值,根据哈希值来决定当前对象在集合中的存储位置。
  • 在存储的时候,如果遇到了哈希值相同的元素,这时集合的底层还会调用当前对象的equals方法,判断当前正要存放的对象和位置上已经存在的对象是否是同一对象,equals方法返回的true,就认为相同对象,不保存,如果equals方法返回的false,当前对象也会被保存。

Set集合可以使用传统for循环来执行遍历吗?

  • 不可以,
  • Set接口不存在get方法,也就是没有List接口通过索引取值的方法。

5. Map集合

Java中提供Map集合主要用来保存具有一定对应关系的数据。在给Map集合中存放对象的时候,一次要求存放一组(一对)对象

Collection接口的所有集合容器统称为**单列集合,Map集合称为双列集合**

Map集合的特点

  1. 存储的时候,每次都要一组一组的进行存储
  2. 无序的集合
  3. key,唯一性;value是可以重复的
  4. 没有提供修改的功能,可以利用key唯一这样的特点,来实现数据的修改

常用方法

  • 增加
    • put(K key, V value) :把当前的key和value存放到集合中。
    • 注意:如果当前的key在集合中已经存在,那么就会用当前的value覆盖key对应的以前的value的值,并且返回被覆盖的那个value值
  • 删除
    • clear();清空
    • remove(Object key) 根据指定的key删除key和value
  • 修改
    • 可以利用新增方法中key唯一实现对元素的修改
  • 获取
    • get(Object key) 根据指定key获取Map集合中key对应的value值,如果key不存在,返回null
    • size() 获取key-value对应关系的个数
  • 判断
    • containsKey(Object key) 判断Map是否包含指定的key,有就返回true
    • containsValue(Object value) 判断Map是否包含指定的value,有就返回true
    • isEmpty() 判断Map集合是否为null,它的size是0
    • keySet(),获取map中所有的key组成一个set集合。
    • entrySet() ,获取map中所有的键值对组成一个set集合。

Map的遍历

  • keySet获取Map集合的key的集合,然后遍历key
for(String key:map.keySet()) {
    System.out.println("key=" + key + "   value=" + map.get(key).toString());
}
  • 通过Map.entrySet遍历key和value
for(Map.Entry<String, Object> entry : map.entrySet()){
    System.out.println("key=" + entry.getKey() + "   value=" + entry.getValue());
}

6. 泛型

限定容器能够存储的数据类型

泛型的应用:<具体的数据类型>

<>尖括号中书写的类型是引用数据类型。不能是基本数据类型

泛型技术,是编译时期技术,在编译源码的时候,会判断泛型指定的类型统一问题,当编译完成之后,生成的class文件中是没有泛型内容。

三、 枚举

枚举指有一组固定的常量组成的类型

可以将枚举看成一种特殊的类,枚举的思想很简单,也很方便,他代表了一组固定的常量值

public  enum  enumname{
   enum-body, //一般写常量
}

四、 包装类

1. 包装类介绍

Java为每种基本数据类型分别设计了对应的类,称之为包装类

其实集合在存储数据的时候,如果存储的是基本数据类型的话,在存储的时候,会将基本数据类型转换成包装类之后在进行存储

描述基本数据类型与之对应的包装类

基本数据类型对应的包装类
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble
booleanBoolean

2. 装箱和拆箱

2.1 装箱

基本类型转为包装类型称为装箱

装箱的方式有三种:1. 直接转换 2. valueOf 3. 构造方法实现转换

  1. 直接定义转换
Integer num1 = 11;
  1. valueof
Integer num2 = Integer.valueOf(num);
  1. 构造方法实现转换
Integer num3 = new Integer(num);
2.2 拆箱

包装类转为基本数据类型称为拆箱

拆箱的方式有两种:1. 直接转换 2. xxxValue

  1. 直接转换
Integer num = 22;
int num1 = num;
  1. xxxValue
Integer num = 22;
int num2 = num.intValue();
Double d = 22.2;
double dd = d.doubleValue();

3. 包装类常用方法

  1. toString 基本类型 -> 字符串

toString():以字符串方式返回包装对象表示的基本数据类型

String str = Integer.toString(88);
String str = Double.toString(33.3);
  1. parseXXX 字符串 -> 基本类型

parseXXX():把字符串转换为相应的基本数据类型数据(Character除外)

long long1 = Long.parseLong("123");
boolean b = Boolean.parseBoolean("true");

五、 Math类和Random类

1. Math类

Java的Math类封装了很多与数学相关的属性和方法

  • abs —— 求绝对值
  • max/min —— 求最大值/最小值
  • random —— 生成一个0-1之间的随机数
  • ceil —— 向上取整
  • floor —— 向下取整
  • round —— 四舍五入 +0.5,向下取整

2. Random类

Random类是一个随机数产生器,构造方法Random()中使用当前的时间来初始化Random对象,因为没有任何时刻的时间是相同的,所以可以减少随机数序列相同的可能性。

Random random = new Random();
int n = random.nextInt();//生成一个整数类型的随机数

Random类的nextInt()方法还可以在有限范围内产生随机数

public int nextInt(int n);

该方法返回一个伪随机数,它是从此随机数生成的序列中取出的 [0,n)之间均匀分布的整型值

六、 String

常用方法

  • charAt(int index) —— 返回指定位置的字符
  • length() —— 求字符串的长度
  • equals() —— 比较两个字符串是否相同
  • equalsIgnoreCase() —— 忽略大小写比较
  • toUpperCase() —— 转换大写
  • toLowerCase() —— 转换小写
  • concat() —— 字符串拼接 , + 是一样的
  • split(String regex) —— 根据给定表达式的匹配拆分字符串,返回字符串数组
方法名说明
public int indexOf(int ch)搜索第一个出现的字符ch(或字符串value),如果没有找到,返回-1
public int indexOf(String value)
public int lastIndexOf(int ch)搜索最后一个出现的字符ch(或字符串value),如果没有找到,返回-1
public int lastIndexOf(String value)
public String substring(int index)提取从位置索引开始的字符串部分
public String substring(int beginindex, int endindex)提取 beginindex 和 endindex 之间的字符串部分
public String trim()返回一个前后不含任何空格的调用字符串的副本

七、 IO

1. IO介绍

IO技术:把程序中的数据最终输出到持久设备上,或者从持久设备读取已经存在的数据,最后给我们读取到程序中。

IO:input 输入 读操作

​ output 输出 写操作

2. file类介绍

在Java中使用**File 这个类来描述持久设备上的文件或者文件夹**

文件:是用来保存真实的数据的

文件夹:管理文件和文件夹

File类常用的构造方法有2个,构造方法可以把对应的文件或文件夹来封装成一个File对象。File没有空参数的构造方法

常用的构造方法

  1. File(String pathname)
  • 把一个字符串描述的文件或文件夹封装成File对象。File类的构造方法会把指定的内容封装成File对象
  1. File(String parent, String child)
  • 可以把一个文件或文件夹的父目录单独分离出来,然后再结合当前的子目录一起封装成File对象

3. File常用方法

方法名称说明
boolean exists()判断文件或目录是否存在
boolean isFile()判断是否是文件
boolean isDirectory()判断是否是目录
String getPath()返回此对象表示的文件的相对路径名称
String getAbsolutePath返回此对象表示的文件的绝对路径名称
String getName()返回此对象表示的文件或目录的名称
boolean delete()删除此对象指定的文件或目录
boolean createNewFile()创建名称的空文件,不创建文件夹
long length()返回文件的长度,单位为字节,如果文件不存在,则返回0L

4. 字节流

IO流技术: I:Inputstream O:OutputStream

流的分类

  • 按流向划分
    • 输出流 —— OutputStream和Writer作为基类
    • 输入流 —— InputStream和Reader作为基类
  • 按处理数据单元划分
    • 字节流
      • 字节输入流 —— InputStream基类
      • 字节输出流 —— OutputStream基类
    • 字符流
      • 字符输入流 —— Reader基类
      • 字符输出流 —— Writer基类

使用流的目的是把程序中的数据写持久设备上,或者从持久设备上读取数据,在写或者读之前,先要让这个流和持久设备之间建立一个读或者写的通道,只有有了这个通道之后才能在这个通道中开始读写数据。

4.1 InputStream

FileInputStream是InputStream常用子类

FileInputStream流被称为文件字节输入流,意思指对文件数据以字节的形式进行读取操作。

常用的构造方法有:FileInputStream(File file) 和 FileInputStream(String path)

常用的方法

  1. int read():这个方法被调用一次,它运行一次,会从底层读取一个字节数据,当把这个字节读取完成之后,在文件中的隐式光标自动的移动到第一个字节和第二个字节之间,返回的数据是这个字节数据转成int值,当读取到文件的末位时,会返回-1。
  2. int read(byte[] b):这个方法每执行一次,就会从底层读取多个字节数据,把读取到的字节数据存储在byte数组中,返回的int值,是表示当前到底从底层读取了几个字节数据。即就是给byte数组中存储了几个字节数据。如果读取到文件末尾会返回-1.
  3. int read(byte[] b, int off, int len):off从哪里开始读多少
  4. void close():关闭流,在使用完成之后一定要关闭流
4.2 字节读取文件模板
  1. 一次读取一个字节的模板代码
//1.先创建流对象和文件进行关联
FileInputStream fis = new FileInputStream("文件");
//2.定义变量,用来记录从底层文件中读取到的那个字节数据
int ch = 0;
//3.定义循环开始从文件中读取数据
while((ch = fis.read()) != -1) {
    //处理读取到的数据,数据存储在ch空间中
}
//4.关闭流对象
fis.close();
  1. 一次读取多个字节数据模板代码
//1.先创建流对象和文件进行关联
FileInputStream fis = new FileInputStream("文件");
//2.定义数组,用来存储从底层读取的多个字节数据,一般都是1024的整数倍
byte[] buf = new byte[1024];
//3.定义变量,用来记录到底从底层读取了多个字节数据
int len = 0;
//4.使用循环从底层开始读取数据
while((len = fis.read(buf)) != -1) {
    //处理读取到的数据,数据存储在buf数组中,buf中共计存储了len个字节数据,并不一定把buf存满
}
//5.关闭流对象
fis.close();
4.3 OutputStream

OutputStream:专门用来操作字节数据的字节输出流对象。是所有字节输出流的超类,并且是个抽象类,不能直接创建对象

常用方法

  1. write(int b):把字节数据直接写在持久设备上
  2. write(byte[] buf):把字节数组中的数据写在持久设备上
  3. wirte(byte[] buf, int off, int len):把buf字节数组中的数据从off下标开始共计写出len个字节数据
  4. close():关闭流,在使用完成之后一定要关闭流

FileOutputStream是OutputStream的子类

FileOutputStream:是专门用于把程序中的数据写到指定的文件中的输出流对象,这个流主要是用来写字节数据的。

FileOutputStream的构造方法

  1. FileOutputStrean(File file):在创建输出流对象的时候,指定一个文件对象,用于把数据写在指定的这个文件中
  2. FileOutputStream(String pathName):在创建输出流对象的时候,把这个字符串当前一个具体的文件位置,然后把数据写在这个文件中
  3. FileOutputStream(String name, boolean append):append表示是追加还是覆盖,true表示追加,false表示覆盖,默认为false

在使用输出流的时候,如果指定的文件不存在,会自动创建这个文件对象,如果文件存在,会创建一个新的把原来的文件覆盖掉。

注意

  1. 前面两个构造方法如果指定的文件不存在,会自动创建这个文件对象;如果文件存在,会创建一个新的把原来的文件覆盖掉,以前的数据都消失了
  2. 第三个构造方法写数据时,当文件不存在同样会创建一个新的文件;如果文件存在了,第二个参数表示是否追加,flase表示不追加(默认),和其他两个构造方法结果一致,为true时,表示追加,在原来内容的基础上新增内容

5. 字符流

Java给我们提供专门用于操作字符数据的流对象

字符输入流Reader

字符输出流Writer

5.1 Reader

用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()

Reader类常用方法

  • int read():执行一次,会得到一个字符数据,如果读取到文件末尾,返回的-1
  • int read(char[] c):执行一次,会从底层读取多个字符数据,存储在字符数组中,返回本次读取的字符数据个数,如果读取到文件末尾,返回-1
  • read(char[] c, int off, int len):将读取到的数据存储在数组中,从off开始,到len结束
  • void close():关闭流

子类InputStreamReader常用的构造方法,它又称为转换流

InputStreamReader(InputStream in)

InputStreamReader(InputStream in, String charsetName)

FileReader类是InputStreamReader的子类

FileReader(File file)

FileReader(String name)

5.2 字符读取文件模板
//1. 一次读取一个字符数据
//定义字符输入流对象和文件进行关联
FileReader fr = new FileReader("文件");
//定义变量,存储读取到的字符数据
int ch = 0;
//使用循环读取数据
while((ch = fr.read()) != -1){
    //处理读取到的单个字符数据,数据在ch中保存
}
//关闭流对象
fr.close();

//2. 一次读取多个字符数据
//定义字符输入流对象和文件进行关联
FileReader fr = new FileReader("文件");
//定义字符数组,用来存储一次读取到的多个字符数据
char[] buf = new Char[1024];
//定义变量,记录每次读取到字符个数
int len = 0;
//使用循环读取数据
while((len = fr.read(buf)) != -1){
    //处理读取到的数据,数据保存在buf中,buf中共计保存了len个字符数据
}
//关闭流
fr.close();
5.3 BufferedReader

BufferedReader为提高字符流读取文本文件,有一个独有的方法readLine(),又称高效流,带有缓冲区的流

当所有文件信息都获取完成时候,readLine()方法将返回null

注意文档中有空行,读取的时候不是null,而是空内容

BufferedReader常用的构造方法

  • BufferedReader(Reader in):需要接受一个字符流

如果读取文件中出现中文乱码问题,可以考虑指定编码,原则如下:

FileInputStream fis = new FileInputStream("文件路径");
//使用InputStreamReader并设置编码格式
InputStreamReader fr = new InputStreamReader(fis, "UTF-8");
BufferedReader br = new BufferedReader(fr);
5.4 Writer

Writer类常用方法

  • write(String str):写一个字符串
  • write(String str, int off, int len):把str中的字符数据从off开始,共计写len个
  • void close():关闭流
  • void flush():刷新

子类OutputStreamWriter常用的构造方法

  • OutputStreamWriter(OutputStream out)
  • OutputStreamWriter(OutputStream out, String charsetName)

FileWriter类是OutputStreamWriter的子类

  • FileWriter(File file)
  • FileWriter(String name)

注意:

用字符输出流写出数据的时候:

  1. 其实数据不是直接写在文件中,而是把字节数据存储在缓冲区中。如果这时字符输出流的缓冲区没有写满,或者我们没有调用flush方法,或者没有关闭流对象,在程序结束之前,数据依然在缓冲区中,不会被写到文件中。所以要求,在关闭流之前一定要做到刷新操作。
  2. 字符输出流(FileWriter)关联的文件如果不存在,会在指定的位置创建,如果文件存在,在创建流对象的时候,没有指定的true值,这时会创建新的文件覆盖原来的文件。

flush和close的区别

​ flush是把缓冲区的数据刷出到文件中,没有关闭流和文件之间的关联,在刷新之后,依然可以使用流对象继续给文件中写数据

​ close方法在关闭流之前会先调用flush把缓冲区中的数据写到底层文件中,然后把流和文件的关联关系断开。一旦调用close方法,流就已经被关闭了,就无法再使用当前这个流对象写数据。

5.5 BufferedWriter

使用FileWriter和BufferedWriter类可以提高字符流写文件的效率

BufferedWriter常用的构造方法

  • BufferedWriter(Writer out)

6. 流的总结

6.1 字节流:2类

字节输入流:

​ InputStream:它是字节输入流的超类,它中定义字节输入流的基本操作方法

​ close():关闭流对象

​ read():一次读取一个字节数据

​ read(byte[] buf):一次读取多个字节数据,存储在buf中,然后给buf中读取的字节个数

​ FileInputStream:专门用来读取文件中字节数据的文件字节输入流对象

​ 创建这个类的对象,读取文件中的数据

//模板代码:
//1. 一次读取一个字节
FileInputStream fis = new FileInputStream("文件");
int ch = 0;
while((ch = fis.read()) != -1){
    //处理读取到的数据,数据在ch中
}
fis.close();
//2. 一次读取多个字节数据
FileInputStream fis = new FileInputStream("文件");
byte[] buf = new byte[1024];
int len = 0;
while((len = fis.read(buf)) != -1) {
    //处理数据,数据在buf中,共计len个
}
fis.close();

字节输入流:

​ OutputStream:字节输出流的超类,它中定义的基本的输出字节数据的操作

​ close():关闭流对象

​ write(int b):写出一个字节数据,注意只能把这个int数据中的最低1个字节数据写出去

​ write(byte[] buf):把字节数组中的所有数据写到文件中

​ write(byte[] buf,int off,int len):把字节数组中的数据从off开始,共计写len个

​ FileOutputStream:它是专门用来给文件中写字节数据的流对象。使用输出流写数据的时候,如果对应的文件不存在会新建一个文件,如果文件存在,在创建对象的时候,没有指定true值,就会继续创建新的文件,覆盖原来的文件。

一般会在读的while循环中使用写的功能,往出把读取到的数据写出去。

6.2 字符流:2类

字符输入流:

​ Reader:是所有字符输入流的超类

​ close():关闭流对象

​ read():一次读取一个字符数据,但返回的字符数据的编码值

​ read(char[] buf):一次读取多个字符数据,把数据存储在buf中,返回读取的字符个数

​ FileReader:专门用于读取字符文件字符输入流对象,它内部使用本地默认的编码表(GBK)

字符输出流:

​ Writer:是所有字符输出流的超类

​ close():关闭流对象

​ write(int b):写出一个字符数据 write(‘a’):这个会把这个a转成97,再写出去

​ 字符数据和int数据在一定范围内可以相互赋值

​ write(char[] buf):把buf数组中的数据全部写出去

​ write(char[] buf,int off,int len):把buf中的数据从off开始共计写len个

​ write(String s):把一个字符串写出去

​ FileWriter:专门用于给字符文件中写字符数据的便捷类,它的底层使用的默认的编码表和默认的缓冲区

7. DataInputStream

在IO包中提供了两个与平台无关的数据操作流

  • 数据输出流:DataOutputStream
  • 数据输入流:DataInputStream

其使用方法和字节流类似

DataInputStream类

  • FilterInputStream的子类
  • 与FileInputStream类结合使用读取二进制文件
  • 构造方法:DataInputStream(InputStream in)

DataOutputStream类

  • FilterOutputStream的子类
  • 与FileOutputStream类结合使用写二进制文件
  • 构造方法:DataOutputStream(OutputStream out)

8. 序列化和反序列化

序列化用与将对象状态转换为字节流的过程。需要使用对象输出流ObjectOutputStream。 对象 -> 文件 —— 写的过程

​ 我们使用new关键字创建在内存中的对象,包括对象中的所有数据,持久性的保存到硬盘上,通常是文件中, 对象 -> 文件

反序列化从特定的流中获取数据重新构建对象的过程。需要使用对象输入流ObjectInputStream。 文件 -> 内存 —— 读的过程

​ 保存在文件中的对象通过反序列化的手段从新加载在内存中

对象的序列化主要有两种用途:

  1. 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中
  2. 在网络上传送对象的字节序列

注意:

  1. 序列化和反序列化都是基于二进制流的,也就是说,在信息转化为二进制存储在文件中之后,用文本编辑器打开查看的话,肯定是会出现乱码的。只有通过反序列化才能将存储的二进制读取出来,然后正常显示在控制台上。
  2. 如果一个对象要实现序列化的话,则这个类必须要实现一个序列化的接口

实现序列化:序列化是写的过程

在这里插入图片描述

实现反序列化:反序列化是读的过程

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值