目 录
一、装饰器设计模式
1.说明
2.实例
3.实例类图
二、压缩流
1.GZipOutputStream
2.GZipInputStream
三、字节数组流
1.说明
2.实例
3.对象流装饰字节数组
四、对象克隆
1.clone() 的克隆
2.序列化和反序列化的克隆
3.字节数组流的深克隆
一、装饰器设计模式
1.说明
- 23 种设计模式之一,属于结构型设计模式;
- 通过编写大量子类来继承父类,重写父类中的方法,会导致子类数量翻倍,即类爆炸;
- 装饰器模式可以在不修改原代码的基础上完成功能扩展,符合 OCP 原则,避免了继承所带来的类爆炸问题;
- IO 流中大量使用了装饰器模式;
- 角色:
- 组件:定义一个对象接口,可以给这些对象动态地添加职责。它是被装饰者和装饰者共同实现的接口。
- 具体组件:实现了组件接口,是被装饰的原始对象,定义了基本的行为。
- 装饰器:持有一个组件对象的引用,并实现了组件接口。它的主要作用是为具体组件添加额外的功能。
- 具体装饰器:具体实现装饰器,负责向组件添加具体的额外功能。
- 装饰者和被装饰者应当实现相同接口 / 抽象类;
- 装饰者应含有被装饰者的引用,引用类型应该是抽象的、不是具体的。
2.实例
java">/*** 接口*/
public interface Eatable {void eat();
}
java">/*** 所有装饰者的父类*/
public abstract class EatableDec implements Eatable {protected Eatable eatable;public EatableDec(Eatable eatable) {this.eatable = eatable;}@Overridepublic void eat() {}
}
java">/*** 装饰者1*/
public class DoDec extends EatableDec {public DoDec(Eatable eatable) {super(eatable);}@Overridepublic void eat() {System.out.println(eatable + "开始吃饭!");super.eat();System.out.println(eatable + "吃饭结束!");}
}
java">/*** 装饰者2*/
public class TimeDec extends EatableDec {public TimeDec(Eatable eatable) {super(eatable);}@Overridepublic void eat() {Date now = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println(sdf.format(now) + eatable + "开始吃饭!");super.eat();}
}
java">/*** 被装饰者1*/
public class Man implements Eatable{@Overridepublic void eat() {System.out.println("Man eat");}
}
java">/*** 被装饰者2*/
public class Woman implements Eatable {@Overridepublic void eat() {System.out.println("Woman eat");}
}
java">public class Test {public static void main(String[] args) {Eatable e1 = new DoDec(new Man());Eatable e3 = new TimeDec(new Man());Eatable e2 = new DoDec(new Woman());Eatable e4 = new TimeDec(new Woman());e1.eat();e3.eat();e2.eat();e4.eat();}
}
3.实例类图
二、压缩流
1.GZipOutputStream
java">public class GZipOutputStreamTest {public static void main(String[] args) {try (FileInputStream fileInputStream = new FileInputStream("D:\\Test.txt");GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new FileOutputStream("D:\\Test.txt.gz"))) {byte[] bytes = new byte[1024];int readCount = 0;while ((readCount = fileInputStream.read(bytes)) != -1) {gzipOutputStream.write(bytes, 0, readCount);}} catch (IOException e) {throw new RuntimeException(e);}}
}
2.GZipInputStream
java">public class GZipInputStreamTest {public static void main(String[] args) {try (GZIPInputStream gzipInputStream = new GZIPInputStream(new FileInputStream("D:\\Test.txt.gz"));FileOutputStream fileOutputStream = new FileOutputStream("D:\\Java\\Test.txt")) {byte[] bytes = new byte[1024];int readCount = 0;while ((readCount = gzipInputStream.read(bytes)) != -1) {fileOutputStream.write(bytes, 0, readCount);}} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);}}
}
三、字节数组流
1.说明
- 字节数组流是内存流;
- ByteArrayInputStream 和 ByteArrayOutputStream 都是内存操作流,无需 打开 / 关闭 文件等操作,能够方便地读写字节数组、图像数据等内存中的数据;
- ByteArrayInputStream 和 ByteArrayOutputStream 都是节点流。
2.实例
java">public class ByteArrayOutputStreamTest {public static void main(String[] args) {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();byteArrayOutputStream.write(97);byteArrayOutputStream.write(98);byteArrayOutputStream.write(99);byteArrayOutputStream.write(100);byteArrayOutputStream.write(101);byte[] byteArray = byteArrayOutputStream.toByteArray();for (byte b : byteArray) {System.out.print(b + "\t");}// 97 98 99 100 101}
}
3.对象流装饰字节数组
注意:由于包装流有缓存,所以使用包装流就要手动刷新。
java">public class ByteArrayOutputStreamTest {public static void main(String[] args) {try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {objectOutputStream.writeByte(1);objectOutputStream.writeChar('a');objectOutputStream.writeShort(100);objectOutputStream.writeInt(6666);objectOutputStream.writeLong(99999);objectOutputStream.writeFloat(1.1f);objectOutputStream.writeDouble(2.2);objectOutputStream.writeBoolean(true);objectOutputStream.writeObject("hello");objectOutputStream.flush();byte[] byteArray = byteArrayOutputStream.toByteArray();ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray);ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);System.out.println(objectInputStream.readByte()); // 1System.out.println(objectInputStream.readChar()); // aSystem.out.println(objectInputStream.readShort()); // 100System.out.println(objectInputStream.readInt()); // 6666System.out.println(objectInputStream.readLong()); // 99999System.out.println(objectInputStream.readFloat()); // 1.1System.out.println(objectInputStream.readDouble()); // 2.2System.out.println(objectInputStream.readBoolean()); // trueSystem.out.println(objectInputStream.readObject()); // hellobyteArrayInputStream.close();objectInputStream.close();} catch (IOException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}
}
四、对象克隆
1.clone() 的克隆
之前在面向对象章节谈过的一种克隆方式,调用 Object 的 clone 方法默认是浅克隆,深克隆需要重写 clone 方法。参考链接如下:
Java基础关键_007_面向对象(二)https://mp.csdn.net/mp_blog/creation/editor/145369813
2.序列化和反序列化的克隆
在第三节谈到的序列化和反序列化也可以完成对象的克隆。参考链接如下:
Java基础关键_025_IO流(三)https://mp.csdn.net/mp_blog/creation/editor/146349119
3.字节数组流的深克隆
将要克隆的 Java 对象写到内存中的字节数组,再从内存中的字节数组读取,读取到的对象就是一个深克隆。
java">public class Student implements Serializable {@Serialprivate static final long serialVersionUID = 1L;private String name;private int age;public Student(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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
java">public class Teacher implements Serializable {@Serialprivate static final long serialVersionUID = 0L;private String name;private Student student;public Teacher(String name, Student student) {this.name = name;this.student = student;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Student getStudent() {return student;}public void setStudent(Student student) {this.student = student;}@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", student=" + student +'}';}
}
java">/*** 利用 ByteArrayOutputStream 和 ByteArrayInputStream 实现深拷贝*/
public class BAOISClone {public static void main(String[] args) {Teacher teacher = new Teacher("鬼谷子", new Student("孙膑", 18));try (ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos)) {oos.writeObject(teacher);oos.flush();byte[] byteArray = baos.toByteArray();ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);ObjectInputStream ois = new ObjectInputStream(bais);Teacher teacherClone = (Teacher) ois.readObject();System.out.println("原teacher:" + teacher);System.out.println("克隆teacher" + teacherClone);System.out.println("=====================================");teacherClone.setName("孔子");teacherClone.getStudent().setName("颜回");teacherClone.getStudent().setAge(20);System.out.println("原teacher:" + teacher);System.out.println("克隆teacher" + teacherClone);} catch (IOException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}
}