管道流、BufferedReader类、对象序列化

1.管道流
管道流的主要作用是可以进行两个线程间的通信。分为管道输出流(PipedOutputStream)和管道输入流(PipedInputStream)。如果要进行管道输出,则必须把输出流连在输入流上,在PipedOutputStream类上有如下方法用于连接管道。
public void connect(PipedInputStream snk)throws IOException
验证管道流:
package com.test;

class Send implements Runnable{
	private PipedOutputStream pos = null;
	public Send() {
		this.pos = new PipedOutputStream();			// 实例化输出流 
	}
	@Override
	public void run() {
		String str = "Hello World!!!";
		try {
			this.pos.write(str.getBytes());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			this.pos.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public PipedOutputStream getPos() {
		return pos;
	}
}

class Receive implements Runnable{
	private PipedInputStream pis = null;
	public Receive() {
		this.pis = new PipedInputStream();
	}
	@Override
	public void run() {
		byte[] b = new byte[1024];
		int len = 0;
		try {
			len = this.pis.read(b);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			this.pis.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(new String(b,0,len));
	}
	public PipedInputStream getPis() {
		return pis;
	}

}
public class Demo1 {
	public static void main(String[] args) {
		Send send = new Send();
		Receive receive = new Receive();
		try {
			send.getPos().connect(receive.getPis());
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		new Thread(send).start();
		new Thread(receive).start();
	}
}


2.BufferedReader类
BufferedReader类用于从缓冲区中读取内容,所有的输入字节数据都将存放在缓冲区中。
BufferedReader类的常用方法:
public BufferedReader(Reader in) 构造函数,接收一个Reader类的实例
public String readLine() throws IOException 一次性从缓冲区中将内容全部读取进来
BufferedReader中定义的构造方法只能接收字符输入流的实例,所以必须使用字符输入流和字节输入流的转换类InputStreamReader将字节输入流System.in变为字符流。

public class Demo2 {
	public static void main(String[] args) {
		BufferedReader buf = null;
		buf = new BufferedReader(new InputStreamReader(System.in));
		String str = null;
		System.out.println("please input:");
		try {
			str = buf.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("you write:"+str);
	}
}
//相关操作实例:
//①现在要求从键盘输入两个数字,然后完成两个整数的加法操作。因为从键盘接收过来的内容全部是采用字符串的形式存放的,
//所以直接将字符串通过包装类Integer将字符串变为基本数据类型。
public class Demo3 {
	public static void main(String[] args) throws  Exception {
		int i = 0;
		int j = 0;
		BufferedReader buf = null;
		buf = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("请输入第一个数字:");
		i = Integer.parseInt(buf.readLine());
		System.out.println("请输入第二个数字:");
		j = Integer.parseInt(buf.readLine());
		System.out.println("sum="+(i+j));
	}
}

以上程序已经实现了题目所需要的内容,但是还存在以下几个问题:
a.如果输入的字符串不是数字,则肯定无法转换,会出现数字格式化异常,所以在转换时应该使用正则进行验证。
b.只能输入整数
c.代码重复,只要输入数据,则肯定使用BufferedReader,重复出现readLine()调用
②对类进行合理的划分:
对于输入数据,最常见的可能是整数、小数、日期、字符串,所以此时最好将其设计一个专门的输入数据类,完成输入数据的功能。

class InpuData{
	private BufferedReader buf = null;
	public InpuData() {
		buf = new BufferedReader(new InputStreamReader(System.in));
	}
	public String  getString(String info) {
		String temp = null;
		System.out.println(info);
		try {
			temp = this.buf.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return temp;
	}
	public int getInt(String info,String err) {
		int temp = 0;
		String str = null;
		boolean flag = true;
		while (flag) {
			str = this.getString(info);
			if (str.matches("^\\d+$")) {
				temp = Integer.parseInt(str);
				flag = false;
			} else {
				System.out.println(err);
			}
		}
		return temp;
	}
}
③对输入数据类的进一步扩充
在开发中最常见的输入数据类型就是整数、小数、字符串、日期,下面进一步扩充InputData类,输入各种类型的数据。

public float  getFloat(String info,String err) {
	String str = null;
	float temp = 0;
	boolean flag = true;
	while (flag) {
		str = this.getString(info);
		if (str.matches("^\\d+.?\\d+$")) {
			temp = Float.parseFloat(str);
			flag = false;
		} else {
			System.out.println(err);
		}
	}
	return temp;
}
public Date getDate(String info,String err) {
	String str = null;
	Date d = null;
	boolean flag = true;
	while (flag) {
		str = this.getString(info);
		if (str.matches("^\\d{4}-\\d{2}-\\d{2}$")) {
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
			try {
				d = format.parse(str);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			flag = false;
		} else {
			System.out.println(err);
		}
	}
	return d;
}


3.对象序列化
对象序列化就是把一个对象变为二进制的数据流的一种方法,通过对象序列化可以方便地实现对象的传输或存储。
如果一个类的对象想被序列化,则对象所在的类必须实现java.io.Serializable接口。此接口的定义如下:
public interface Serializable{}    可以看到这个接口中没有定义任何方法,所以此接口是一个标识接口。标示一个类具备了被序列化的能力。
①对象输出流ObejectOutputStream:
ObjectOutputStream常用方法:
public ObjectOutputStream(OutputStream out)throws IOException构造方法,传入输出的对象
public final void writeObeject(Object obj)throws IOException 


class People implements Serializable{
	private String name;
	private int age;
	public People(String name,int age) {
		this.name = name;
		this.age = age;
	}

}

public class Demo5 {
	public static void main(String[] args) throws Exception {
		File file = new File("d:"+File.separator+"a.txt");
		OutputStream outputStream = new FileOutputStream(file);
		ObjectOutputStream stream = new ObjectOutputStream(outputStream);
		stream.writeObject(new People("王某", 29));
		stream.close();
	}
}	

到底序列化了哪些内容?
只有属性被序列化,每个对象都具备相同的方法,但是每个对象的属性不一定相同,也就是说,对象保存的只有属性信息,那么在序列化操作时也同样是这个道理,只有属性被序列化。
当使用Serializable接口实现序列化操作时,如果一个对象中的某个属性不希望被序列化,则可以使用transient关键字进行声明。
②对象输入流ObjectInputStream:(反序列化)
ObjectInputStream常用方法:
public ObjectInputStream(InputStream in)throws IOException 构造函数,构造输入对象
public final Object readObject()throws IOException,ClassNotFoundException 从指定位置读取对象

class People implements Serializable{
	private String name;
	private int age;
	public People(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 "name="+this.getName()+",age="+this.getAge();
	}
}

public class Demo5 {
	public static void main(String[] args) throws Exception {
		File file = new File("d:"+File.separator+"a.txt");		
		InputStream inputStream = new FileInputStream(file);
		ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
		Object object = objectInputStream.readObject();
		objectInputStream.close();
		System.out.println(object);
	}
}
③Externalizable接口
被Serializable接口声明的类的对象的内容都将被序列化,如果现在用户希望自己指定序列化的内容,则可以让一个类实现Externalizable接口
Externalizable接口是Serializable接口的子接口,在这个接口中定义了两个方法,这两个方法的作用如下:
writeExternal(ObjectOutput out):在此方法中指定要保存的属性信息,对象序列化时调用
readExternal(ObjectInput in):在此方法中读取被保存的信息,对象反序列化时调用
如果一个类要使用Externalizable实现序列化,在此类中必须存在一个无参构造方法,因为在反序列化时会默认调用无参构造实例化对象。
class Person implements Externalizable{
	private String name;
	private int id;
	public Person() {
		// TODO Auto-generated constructor stub
	}
	public Person(String name, int id) {
		this.name = name;
		this.id = id;
	}
	@Override
	public void writeExternal(ObjectOutput out) throws IOException {
		out.writeObject(this.name);
		out.writeInt(this.id);
	}
	@Override
	public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
		this.name = (String) in.readObject();
		this.id = in.readInt();
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值