Java学习总结(8)—内存流,打印流,对象流,RandomAccessFile,装饰者设计模式

一.内存流

  1. 内存流主要用来操作内存
  2. BytearrayInputStream和ByteArrayOutputStream输入和输出可以把文件作为数据源,也可以把内存作为数据源

    (1)ByteArrayInputStream主要完成将内容从内存读入到程序中,而ByteArrayOutputStream的主要功能是是将数据写入到内存中

    (2)注意:因为这两个流没有使用系统资源,所以不用关闭,也不需要抛出异常

  3. 内存操作示意图

    (1)从程序中读:程序<—ByteArrayInputStream<—内存数据

    (2)向内存中写:程序—>ByteArrayOutputStream<—内存数据

  4. ByteArrayOutputStream获取数据的方式

    (1)public byte[] toByteAarray():创建一个新分配的字节数组,它的大小 是这个输出流的当前大小和缓冲区的有效内容的副本

    (2)public Stirng toString():使用该平台默认的字符集将缓冲区的内容的转换为字符串

例1(利用内存流复制图片):

package bytestream;

import java.io.*;

public class ByteOutputStreamDemo {

    public static void main(String[] args) {

File srcFile = new File("d:" + File.separator + "1TX761XVUM10.jpg");// 源文件地址

File destFile = new File("e:" + File.separator + srcFile.getName());// 目标文件地址

InputStream input = null;// 输入流

OutputStream out = null;// 输出流

ByteArrayOutputStream bos = new ByteArrayOutputStream();// 内存流

        try {

input = new FileInputStream(srcFile);// 对象用于读取源文件

out = new FileOutputStream(destFile);// 对象用于写入目标文件

            byte[] b = new byte[1024];

            int len = 0;

// 边读编写

System.out.println("开始复制文件!");

            while ((len = input.read(b)) != -1) {

bos.write(b, 0, len);

}

            byte[] date = bos.toByteArray();// 创建一个新的字节数组,他的大小是这个输出流的当前大小,和缓冲区的有效    内容的副本

out.write(date);// 讲缓冲区中的内容一次性写入到目标文件中

System.out.println("文件复制完毕......");

} catch (Exception e) {

e.printStackTrace();

} finally {

                try {

// 关闭资源

out.close();

input.close();

bos.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

运行结果:开始复制文件!

文件复制完毕.....

例2(以byteArrayInputStream为例):

package bytestream;

import java.io.*;

public class ByteArrayInputStreamDemo {

public static void main(String[] args) {

String date="世界,你好!!!!";

/**

* 内存输入流中传入的参数为要读取的字节数组,故将date

* 转化为字节数组date.getBytes(),再传入内存流中

*/

ByteArrayInputStream  bis = new  ByteArrayInputStream(date.getBytes());

byte[] b=new byte[1024];//自定义缓存区

int len=0;

try {

len=bis.read(b);

System.out.println("读取到的内容是:"+new String(b,0,len));

} catch (IOException e) {

e.printStackTrace();

}

//数据存于缓存区中,缓存流不用关闭

}

}

运行结果:读取到的内容是:世界,你好!!!!

二.打印流

  1. 打印流提供了打印方法,可以将各种数据类型原样打印,可以操作输出流和文件
  2. PrintStream:

    (1)提供操作字节功能

    (2)如果包装的是缓冲流可自动设置flush

    (3)可设置字符集

  3. PrintWriter:

    (1)没有操作字节功能

    (2)内部有缓冲区,即使自动刷新设置为true

    (3)可设置字符集

  4. 打印流的构造方法

    <1>PrintStream的构造方法

    (1)public  PrintStream(File file)

    (2)public  PrintStream(OutputStream out)

    <2>PrintWriter的构造方法

    (1)public  PrintWriter(File file)

    (2)Public  PrintWriter(Writer out)

    (3)Public  PrintWriter(OutputStream out)

例1(写入一首诗到C盘文件下):

package print;

import java.io.*;

public class PrintStreamDemo {

public static void main(String[] args) {

File f=new File("C:"+File.separator+"静夜诗.txt");

PrintStream ps=null;

try {

ps=new PrintStream(f);

ps.println("\t床前明月光");

ps.println("\t疑是地上霜");

ps.println("\t举头望明月");

ps.println("\t低头思故乡");

ps.println("\t\t\t作者:李白");

System.out.println("打印成功...");

} catch (FileNotFoundException e) {

e.printStackTrace();

}finally{

ps.close();

}

}

}

运行结果:打印成功...

例2(PrintStream若包装缓冲流可设置flush):

package print;

import java.io.*;

public class PrintStreamDemo2 {

public static void main(String[] args) {

File f=new File("c:"+File.separator+"兵法.txt");

PrintStream ps=null;

OutputStream out=null;

try {

out=new FileOutputStream(f);

BufferedOutputStream bos= new BufferedOutputStream(out);

ps=new PrintStream(bos);

ps.println("战武七经:");

ps.println("1.孙子兵法");

ps.println("2.六韬.三略");

ps.println("3.吴子");

ps.println("4.司马法");

ps.println("5.孙膑兵法");

ps.flush();//将缓冲流中的数据刷入文件中

System.out.println("打印成功....");

} catch (FileNotFoundException e) {

e.printStackTrace();

}

}

}

运行结果:打印成功....

三.对象流,序列化与反序列化

  1. 相关类

    (1)ObjectOutputStream(用于序列化)

    (2)ObjectInputStream(用户反序列化)

    2.适用对象流可以实现对象不得序列化与反序列化操作

    3.为什么要序列化

    (1)易于保存

    (2)易于保存

    4.序列化与反序列化的过程

    (1)序列化:Java对象——>对象的二进制形式

    (2)反序列化:Java对象<——对象的二进制形式

    *这种方式被称为序列化与反序列化

    <1>序列化是将对象的状态存储到特定的存储介质中的过程(将对象转化成特定的字节序列(二进制)的过程)

    <2>反序列化则是从特定的存储介质中的数据重新构建对象的过程(将对象的二进制形式转化成对象)

    5.序列化的步骤

    (1)实现Serializble接口

    (2)创建对象输出流

    (3)调用writeObject(Object obj)方法将对象写入输出流中

    (4)关闭对象输出流

    6.反序列化步骤

    (1)实现Serializble接口

    (2)创建对象输入流

    (3)调用readObject()方法读取对象

    (4)关闭对象输入流

    @@创建Person用于举例:

    package serializable;

    import java.io.Serializable;

    public class Person implements Serializable {

    /**

    * 对象类,用于序列化

    */

    private static final long serialVersionUID = 1L;

    private String name;

    private int age;

    private double score;

    public Person() {

    super();

    }

    public Person(String name, int age, double score) {

    super();

    this.name = name;

    this.age = age;

    this.score = score;

    }

    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 double getScore() {

    return score;

    }

    public void setScore(double score) {

    this.score = score;

    }

    public static long getSerialversionuid() {

    return serialVersionUID;

    }

    @Override

    public String toString() {

    return "Person [name=" + name + ", age=" + age + ", score=" + score

    + "]";

    }

    }

    例1(序列化普及对象)

    package serializable;

    import java.io.*;

    public class SerialPerson {

    public static void main(String[] args) {

    File f=new File("d:"+File.separator+"Serbial.txt");

    ObjectOutputStream oos=null;

    OutputStream out=null;

    Person per=new Person("Jack",21,98.7);

    try {

    System.out.println("开始序列化");

    out=new FileOutputStream(f);

    oos=new ObjectOutputStream(out);

    oos.writeObject(per);

    System.out.println("系列化 成功......");

    } catch (Exception e) {

    e.printStackTrace();

    }finally{

    try {

    out.close();

    oos.close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    }

    运行结果:开始序列化

    系列化 成功......

    例2(普通反序列化)

    package serializable;

    import java.io.*;

    public class DeSerialPerson {

    public static void main(String[] args) {

    File f = new File("d:" + File.separator + "Serbial.txt");

    InputStream input = null;

    ObjectInputStream ois = null;

    try {

    System.out.println("开始反序列化!!!");

    input = new FileInputStream(f);

    ois = new ObjectInputStream(input);

    Person per=(Person)ois.readObject();

    System.out.println("反序列化成功。。。。。");

    } catch (Exception e) {

    e.printStackTrace();

    }finally{

    try {

    ois.close();

    input.close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    }

    运行结果:开始反序列化!!!

    Person [name=Jack, age=21, score=98.7]

    例3(序列化集合)

    package serializable;

    import java.io.*;

    import java.util.*;

    public class SerialListDemo {

    public static void main(String[] args) {

    File f=new File("d:"+File.separator+"listSer.txt");

    List<Person> list=new ArrayList<Person>();

    Collections.addAll(list, new Person("郭靖",21,96.2),new Person("黄蓉",22,93.2),new Person("小龙女",19,94.6),

    new Person("杨过",15,95.3));

    OutputStream out=null;

    ObjectOutputStream oos=null;

    try {

    System.out.println("开始序列化");

    out=new FileOutputStream(f);

    oos=new ObjectOutputStream(out);

    oos.writeObject(list);

    System.out.println("系列化成功.......");

    } catch (Exception e) {

    e.printStackTrace();

    }finally{

    try {

    out.close();

    oos.close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    }

    运行结果为:

    开始序列化

    系列化成功.......

    例4(反序列化集合)

    package serializable;

    import java.io.File;

    import java.io.FileInputStream;

    import java.io.IOException;

    import java.io.InputStream;

    import java.io.ObjectInputStream;

    import java.util.List;

    public class DeSerialList {

    public static void main(String[] args){

    File f=new File("d:"+File.separator+"listSer.txt");

    InputStream input=null;

    ObjectInputStream ois=null;

    try {

    System.out.println("开始反序列化");

    input=new FileInputStream(f);//输入流

    ois=new ObjectInputStream(input);//封装输入流到对象流中

    List<Person> list=(List<Person>)ois.readObject();//向上 转型

    for(Person per:list){

    System.out.println( per);

    }

    } catch (Exception e) {

    e.printStackTrace();

    }finally{

    try {

    input.close();

    ois.close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    }

    运行结果:

    开始反序列化

    Person [name=郭靖, age=21, score=96.2]

    Person [name=黄蓉, age=22, score=93.2]

    Person [name=小龙女, age=19, score=94.6]

    Person [name=杨过, age=15, score=95.3]

    四.RandomAccessFile

    1.直接继承Object

    2.主要功能是完成随机读写功能,可以读取指定位置的内容

    3.构造方法:
    (1)public RandomAccessFile(File file,String mode)

    (2)public RanaccessFile(String name,String mode)

    (3)只能操作文件

    4.文件的打开模式(mode)

    (1)”r”以只读方式打开,调用结果对象的任何write方法都将抛出异常IOException

    (2)“rw”打开以便于读取和写入,如果该文件上不存在,则尝试创建该文件

    5.RandomAccessFile的常用方法

    (1)void seek(long pos)设置文件指定偏移量, 在该位置准备开始读写

    (2)Int sikpByte(int n)尝试跳过输入的n个字节,返回实际跳过的字节数

    (3)Long getFilePointer()获取此文件中的 当前偏移量

    (4)Long length()返回此文件的长度

    (5)Void write(int) 向此文件写入指定的字节

    (6)Void write(Byte[])将b.length个字节从指定的byte[]数组写入到文件中,并从当前文件指针开始

    (7)Void write(byte[] b,int off,int len)

    (8)int read()向此文件中读取一个数据字节

    (9)int read(byte[] b)将最多b.length个数据字节从此文件读入到byte数组

    (10)int read(byte[] b,int off,int len)

    (11)Void writeBytes(String s)以字节为单位写出字符串,无法写出中文

    (12)Void writeChars(String s)每个字符占两个位置,可以写出中文,使用unicode编码

    (13)Void writeUTF(String str)使用 utf-8编码方式将一个字符串写出到该文件,可以写出中文

    (14)Void witreBoolean(boolean v)

    (15)Void writeByte(int v)

    (16)Void writeChar(int v)

    (17)Void writeInt(int v)

    例1.(以RandomAccessFile基本方法为例)

    package raf;

    import java.io.File;

    import java.io.IOException;

    import java.io.RandomAccessFile;

    public class RandomAccessFileDemo {

    public static void main(String[] args) {

    File f=new File("d:"+File.separator+"Ran.txt");

    RandomAccessFile  raf=null;

    try {

    raf=new RandomAccessFile(f,"rw");

    raf.writeBoolean( true);

    raf.writeChar('A');

    raf.writeChars("hello");

    raf.writeChars("中华人名共和国");

    System.out.println("写入成功.....");

    raf.seek(9);

    System.out.println("文件当前位置指针:"+raf.getFilePointer());

    System.out.println("当前位置字符:"+raf.readChar());

    raf.seek(3);

    System.out.println("文件当前位置指针:"+raf.getFilePointer());

    System.out.println("当前位置字符:"+raf.readChar());

    raf.seek(10);

    System.out.println("文件当前位置 指针"+raf.getFilePointer());

    System.out.println("文件当前位置在字符:"+raf.readChar());

    } catch (Exception e) {

    e.printStackTrace();

    }finally{

    try {

    raf.close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    }

    运行结果:

    写入成功.....

    文件当前位置指针:9

    当前位置字符:l

    文件当前位置指针:3

    当前位置字符:h

    文件当前位置 指针10

    文件当前位置在字符:氀

    例2(RandomAccessaFile注意点)

    package raf;

    import java.io.File;

    import java.io.IOException;

    import java.io.RandomAccessFile;

    public class RafString {

    public static void main(String[] args) {

    File f=new File("d:"+File.separator+"raf.txt");

    RandomAccessFile raf=null;

    try {

    raf=new RandomAccessFile(f,"rw");

    raf.writeBytes("中华人民共和国");//会丢弃高八位的方式写入字符串中的每个字符

    raf. writeChars("中央 人民政府");//会将字符串中的每个字符写入

    raf.seek(3);//设置文件指针

    System.out.println("当前 指针位置的字符为:"+raf.readChar());

    } catch (Exception e) {

    e.printStackTrace();

    }finally{

    try {

    raf.close();

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    }

    运行结果为:

    当前 指针位置的字符为:?

五.装饰者模式

  1. 当需要对已有的对象进行功能增强时,可以定义类(装饰类),将已有的对象的话传入,基于已有的功能,并提供增强功能,那么自定义的类称为装饰 类
  2. 相同点:装饰者模式与继承关系的目的都是要扩展对象的功能
  3. 不同点:

    (1)代码的结构比继承更加简洁

    (2)装饰者模式可以提供比继承更多的灵活性(意味着可以向装饰器的构造方法传入被装饰类的子类对象)

  4. 装饰者设计模式的特点

    (1)装饰对象和真实对象有相同的接口或抽象类

    (2)装饰对象包含一个真实对象的引用

    (3)装饰对象接收所有来自客户端的请求,他把这些请求转发给真实对象

    (4)装饰对像可以在转发这些请求之前或之后增加一些附加的功能

  5. 装饰者设计模式的结构

    (1)抽象构建角色:给出一个抽象接口,以规范准备接受附加责任的对象,相当于IO流中的InputStream/OutputStream

    (2)具体构建角色:定义一个将要接受附加责任的类,相当于IO流中的FileInputStream/FileOutputStream

    (3)抽象装饰角色:持有一个抽象构建角色(也就是Component)的引用,并实现这个与抽象构建接口,相当于FileterInputStream/FileterOutputStream

    (4)具体的装饰角色:负责给构建对象“贴上”附加的责任。相当于BufferedInputStream/BufferedOutputStream

    例.(装饰一个学生的学习方法)

    *抽象构建接口

    package decorator;

    /**

    * 抽象构建接口

    * @author Qitao

    */

    public interface Study {

    public void study();

    }

    *具体构建角色

    package decorator;

    /**

    * 具体构建角色

    * @author Administrator

    */

    public class Student implements Study{

    @Override

    public void study() {

    System.out.println("学生正在学习...");

    }

    }

    *抽象装饰角色

    package decorator;

    /**

    * 抽象装饰角色

    * @author Administrator

    */

    public abstract class Decorator implements Study{

    private Study study;

    public Decorator(Study study) {

    super();

    this.study = study;

    }

    @Override

    public void study() {

    this.study.study();

    }

    }

    *具体装饰角色

    package decorator;

    /**

    * 具体装饰角色

    * @author Administrator

    */

    public class ConcreteDecorator extends Decorator{

    public ConcreteDecorator(Study study) {

    super(study);

    }

    public void goodStudy(){

    System.out.println("课前预习...");

    super.study();

    System.out.println("课后复习...");

    }

    }

    *测试装饰者设计模式类:

    package decorator;

    /**

    * 测试装饰者设计模式

    * @author Administrator

    */

    public class Test {

    public static void main(String[] args){

    Study study=new Student();

    ConcreteDecorator con=new ConcreteDecorator(study);

    con.goodStudy();

    }

    }

    运行结果:

    课前预习...

    学生正在学习...

    课后复习...

原文地址:http://blog.51cto.com/13501268/2071422

时间: 2024-08-29 04:11:28

Java学习总结(8)—内存流,打印流,对象流,RandomAccessFile,装饰者设计模式的相关文章

java学习-----jvm的内存分配及运行机制

VM运行时数据区域: 根据<Java虚拟机规范(第二版)>的规定,JVM包括下列几个运行时区域: 我们思考几个问题: 1.jVM是怎么运行的? 2.JVM运行时内存是怎么分配的? 3.我们写的java代码(类,对象,方法,常量,变量等等)最终存放在哪个区? VM运行时数据区域: 1.程序计数器(program Counter Register):   是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的

疯狂Java学习笔记(55)----------字节流与字符流

字节流与字符流 在java.io包中操作文件内容的主要有两大类:字节流.字符流,两类都分为输入和输出操作.在字节流中输出数据主要是使用OutputStream完成,输入使的是InputStream,在字符流中输出主要是使用Writer类完成,输入流主要使用Reader类完成.(这四个都是抽象类) 处理流的用法: 按照流是否直接与特定的地方(如磁盘.内存.设备等)相连,分为节点流和处理流两类.  节点流:可以从或向一个特定的地方(节点)读写数据.如FileReader 处理流:是对一个已存在的流的

[疯狂Java]I/O:I/O流的最高境界——对象流(序列化:手动序列化、自动序列化、引用序列化、版本)

1. 什么是对象流:序列化/反序列化的概念 1) 对象流是和字节流/字符流同处于一个概念体系的: a. 这么说字节流是流动的字节序列,字符流是流动的字符序列,那么对象流就是流动的对象序列咯? b. 概念上确实可以这样理解,对象流就是专门用来传输Java对象的: c. 但是字节和字符都是非常直观的二进制码(字节本身就是,而字符是一种二进制编码),二进制码的流动是符合计算机的概念模型的,可是对象是一个抽象的东西,对象怎么能像二进制码那样流动呢? d. 其实很好理解,对象流只不过是Java的API而已

JAVA学习第二十八课(常用对象API)- String类

多线程告一段落,开始常用对象API的涉及,背也要背下来!!! 日后开发,遇见最多的对象是文字,也就是字符串 String类 字符串是一个特殊对象 字符串一旦初始化就不可以被改变 一.特点 public class Main { public static void main(String[] args) { Demo1(); System.out.println("--------------"); Demo2(); } /*演示字符串的第一种定义方式,并明确字符串常量池的特点*/ p

Java学习之创建对象内存使用机制

Java内存空间分两种,一种是栈内存,有多个,一种是堆内存,只有一个,在堆内存中又有一块方法区. 方法区中存储的是:类的信息(类名,类的直接父类,类的访问修饰符),类变量,类方法代码,实例方法代码,常量池.注意没有实例变量. 当使用new创建一个对象的时候,JVM实际上做了三件事:加载类,创建该类的对象,初始化. 加载类就是把类加载方法区,有类信息,类变量,类方法,实例方法,常量(包含字符串常量),加载完后,需要在堆内存中开辟一块空间,完成对象的创建.堆内存中的对象空间只有实例变量,包括基本数据

java学习笔记_内存分析

程序执行时内存一般被分为4部分 代码区(code segment):存放代码 数据区(data segment):静态变量和字符串常量 栈(stack): 存放局部变量 堆(heap):动态生成内存(new出来的东西) 代码如下: public class Person{ int id; int age; Person(int _id,int _age){ id = _id; age = _age; } public static void main(String[] args){ Person

JAVA学习(1):保证类的对象在内存中唯一

一.饿汉式 class Single { private static final Single s=new Single(); private Single(){} public static Single getInstance() { return s; } } 为什么方法是静态的:不能new对象却想调用类中方法,方法必然是静态的,静态方法只能调用静态成员,所以对象也是静态的. 为什么对象的访问修饰符是private,不能是public 吗?不能,如果访问修饰符是Public,则Singl

JAVA学习第三十三课(常用对象API)- 集合框架(一)

数字有很多用数组存,对象有很多就要用集合存 但是数组是固定长度的,集合是可变长度的 集合的由来: 对象用来封装特有数据,对象多了需要存储,如果对象个数不确定,就需要使用集合容器来存储 集合的特点: 1.用于存储对象的容器 2.长度可变 3.集合中不可存储基本数据类型 对于集合体系,的最顶层存储的是该体系中所有的共性内容,Collection,同继承一样,看顶层,用底层 java.uitil包中的Cellection 集合容器因为内部的数据不同,有多种具体容器,不断向上抽取,就形成了集合框架 整个

JAVA学习第三十课(常用对象API)- String类:类方法练习

intern方法 public class Main { public static void main(String[] args) { String str1 = new String("asd"); String str2 = str1.intern();/* 字符串常量池中有,就返回字符串,没有就创建 */ System.out.println(str2); System.out.println( str1 == str2 ); } } 练习1:字符串数组排序 import j