Java基础学习19之BufferedReader类、Scanner、对象序列化

1,426 阅读6分钟

Java基础学习19之BufferedReader类、Scanner、对象序列化

「这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战」。

关于作者

  • 作者介绍

🍓 博客主页:作者主页
🍓 简介:JAVA领域优质创作者🥇、一名在校大三学生🎓、在校期间参加各种省赛、国赛,斩获一系列荣誉🏆。
🍓 关注我:关注我学习资料、文档下载统统都有,每日定时更新文章,励志做一名JAVA资深程序猿👨‍💻。


BufferedReader类

BufferedReader属于一个缓冲的输入流,而且是一个字符流的操作对象。但是必须清楚一点就是对于我们的缓存流定义有两类:字节缓冲流( BufferedInputStream )、字节缓冲流( BufferedReader )。

如果说想在把所有的输入数据放在一起了,一次性读取出来,那么这个时候肯定就能够避免中文问题了,而这一操作就必须依靠缓冲区操作流完成。对于缓冲区的读取在IO包中定义了两种类:BufferedInputStream,BufferedReader,但是考虑到本次操作有中文的问题,肯定使用BufferedReader类完成操作。下面就需要观察一下BufferedReader类的继承结构,构造方法,操作方法:

继承结构:java.lang.Object
java.io.Reader
java.io.BuffereedReader
构造方法:public BuffereedReader(Reader in)
读取操作:public String readLine() throws IOException

之所以选择BufferReader类操作提供的readLine()方法,这个方法可以读取一行数据以回车为准。

image-20210819191629741

使用BufferedReader进行数据读取

package com.day15.demo;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class BufferReaderDemo {
	public static void main(String[] args) throws Exception{
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("请输入");
		//默认的换行模式是BufferReader最大的缺点
		String str = bufr.readLine();//接受输入信息,默认使用回车换行
		System.out.println(str);
	}
}

对输入的数据进行验证,判断是否是数字

package com.day15.demo;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class BufferReaderDemo {
	public static void main(String[] args) throws Exception{
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("请输入年龄");
		//默认的换行模式是BufferReader最大的缺点
		String str = bufr.readLine();//接受输入信息,默认使用回车换行
		if(str.matches("\\d{1,3}"))
			System.out.println(str);
		else
			System.out.println("输入数据有误!");
	}
}

Scanner

这个类是作为了一个工具类出现的,在Scanner之中定义两个如下的一些方法:

public Scanner(InputStream sourse);构造方法
public Boolean hasNextXxx();判断是否有数据
public 数据类型 nextXxx();取得数据
public Scanner useDelimiter(String partern);定义分隔符

以后调用的时候在执行nextXxx()之前一定要首先使用hasNextXxx()判断是否有指定格式的数据出现。

通过Scanner类进行数据的输入

package com.day15.demo;

import java.util.Scanner;

public class ScannerDemo {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入数据:");
		if(sc.hasNext()){//现在有输入的内容,不能判断空字符串
			System.out.println(sc.next());
		}
		sc.close();
	}
}

使用Scanner类判断输入数据是否是int型数据

package com.day15.demo;

import java.util.Scanner;

public class ScannerDemo {
	public static void main(String[] args) {
		System.out.println("请输入数据:");
		Scanner sca=new Scanner(System.in);
		if(sca.hasNextInt()){
			int date=sca.nextInt();
			System.out.println("输入的数据是:"+date);
		}else{
			System.out.println("输入的不是数字");
		}
	}
}

在Scaner类之中,useDelimiter()方法的输入针对于字符串,但是其他的数据类型并不方便使用。

使用Scanner类判断用户输入的是不是生日

package com.day15.demo;

import java.util.Scanner;

public class ScannerDemo {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入生日:");
		if(sc.hasNext("\\d{4}-\\d{2}-\\d{2}")){//现在有输入的内容,不能判断空字符串
			String bir = sc.next("\\d{4}-\\d{2}-\\d{2}");
			System.out.println(bir);
		}
		sc.close();
	}
}

Scanner读取文件内容

package com.day15.demo;

import java.io.File;
import java.io.FileInputStream;
import java.util.Scanner;

public class ScannerDemo {
	public static void main(String[] args) throws Exception{
		Scanner sc = new Scanner(new FileInputStream(new File("f:" + File.separator + "test" + File.separator + "hello.txt")));
		sc.useDelimiter("\n");
		if(sc.hasNext()){//现在有输入的内容,不能判断空字符串
			System.out.println(sc.next());
		}
		sc.close();
	}
}

除了二进制文件拷贝处理之外,只要针对于程序的信息输出都使用打印流,对于信息的输入都是Scanner。

对象序列化

所有的项目都一定有序列化的概念。

对象序列化的概念

所谓的对象序列化是指在内存中保存的对象变为二进制流的形式进行传输,或者将其保存在文本中。但是我们并不意味着所有对象都可以被序列化,严格来讲,我们需要被实例化的类对象往往需要传输使用,同时这个类 必须实现java.io.Serializable接口。但是这个接口没有任何方法定义,所以只是一个标识。

package com.day15.demo;

import java.io.Serializable;

class Person implements Serializable{
	private String name;
	private int age;
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}
public class SerializableDemo {

}

序列化对象是所需要保存的就是对象中的属性所以默认情况下对象的属性将被转为二进制数据流存储。

实现序列化和反序列化

如果要想进行对象的序列化和反序列话的手工操作,在java之中提提供了两个操作类:ObjectOutputStream,ObjectInputStream,而这两个类的继承结构,构造方法,操作方法定义如下:

ObjectOutputStreamObjectInputStream
java.lang.Object
java.io.OutputStream
java.io.ObjectOutputStream
java.lang.Object
java.io.InputStream
java.io.ObjectInputStream
public ObjectOutputStream(OutputStream out)
throws IOException
public ObjectInputStream(InputStream in)
throws IOException
public final void writeObject(Object obj)
throws IOException
public final Object readObject()
throws IOException,ClassNotFoundException

image-20210819210231615

image-20210819210310589

实现对象的序列化操作

package com.day15.demo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;

class Person implements Serializable{
	private String name;
	private int age;
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}
public class SerializableDemo{
	public static final File FILE = new File("F:" + File.separator + "test" + File.separator + "person.txt");
	public static void ser(Object o) throws Exception {
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(FILE));
		outputStream.writeObject(o);
		outputStream.close();
	}
	public static void dser() throws Exception {
		ObjectInputStream inputStream = new	ObjectInputStream(new FileInputStream(FILE));
		System.out.println(inputStream.readObject());
		inputStream.close();
	}
	public static void main(String[] args) throws Exception{
        //序列化
		//ser(new Person("张麻子",20));
        //反序列化
		dser();
	}
}

如果出现com.day15.demo.Person@6d311334这个情况的主要原因是因为实体类没有进行toString()方法的重写。

transient关键字(了解)

实际上序列化的处理在Java.io有两类,Serializable是使用最多的序列化接口,这种操作采用自动化的模式完成,默认情况下所有的属性都会进行序列化。有一个Externalizable接口需要用户手动序列化处理。

由于默认情况Serializable会将对象中的所有属性进行保存,但是如果现在有某些属性不希望被保存了,那么可以使用transient关键字。

使用transient

package com.day15.demo;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;

class Person implements Serializable{
	private transient String name;
	private int age;
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}
public class SerializableDemo{
	public static final File FILE = new File("F:" + File.separator + "test" + File.separator + "person.txt");
	public static void ser(Object o) throws Exception {
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(FILE));
		outputStream.writeObject(o);
		outputStream.close();
	}
	public static void dser() throws Exception {
		ObjectInputStream inputStream = new	ObjectInputStream(new FileInputStream(FILE));
		System.out.println(inputStream.readObject());
		inputStream.close();
	}
	public static void main(String[] args) throws Exception{
		ser(new Person("张麻子",20));
		dser();
	}
}
/*
Person [name=null, age=20]
*/

发现此处name没有进行序列化操作。使用序列化往往在简单java类上使用,其他类上使用序列化的使用很少,但是在简单java类中基本上不去使用transient。