今天学了什么
(1)I/O字符流 Reader: 在Reader里包含如下3个方法: ? int read():从输入流中读取单个字符,返回所读取的字符数据(字符数据可直接转换为int类型)。 int read(char[]cbuf):从输入流中最多读取cbuf.length个字符的数据,并将其存储在字符数组cbuf中,返回实际读取的字符数。 int read(char[]cbuf,int off,int len):从输入流中最多读取len个字符的数据,并将其存储在字符数组cbuf中,放入数组cbuf中时,并不是从数组起点开始,而是从off位置开始,返回实际读取的字符数。 对比InputStream和Reader所提供的方法,就不难发现这两个基类的功能基本是一样的,只是InputStream读取的最小单位是字节,而Reader读取的最小单位是字符。 Writer: Writer抽象类中的方法和OutputStream方法类似,只需要将方法参数中的byte[]更换成char[]即可,字符流直接以字符作为操作单位,所以Writer可以用字符串来代替字符数组,即以String对象作为参数。Writer里还包含如下两个方法。 ? void write(String str):将str字符串里包含的字符输出到指定输出流中。 void write(String str,int off,int len):将str字符串里从off位置开始,长度为len的字符输出到指定输出流中。
/**
?* 字符输入流
? ?*/
? ?public class FileCharInputDemo {
? ?public static void main(String[] args) {
? ? ? ?try(Reader reader = new FileReader("D:\\IoDemo\\filename.txt");
? ? ? ? ? ?Writer writer = new FileWriter("D:\\IoDemo\\text3.txt")){
? ? ? ? ? ?String s;
? ? ? ? ? ?BufferedReader bufferedReader = new BufferedReader(reader);
? ?// ? ? ? ? ? ?int k = 0;
? ?// ? ? ? ? ? ?char[] chars = new char[4];
? ? ? ? ? ?while ((s = bufferedReader.readLine())!=null){
? ?// ? ? ? ? ? ? ? ?String s = new String(chars);
? ? ? ? ? ? ? ?System.out.print(s);
? ? ? ? ? ? ? ?//将读取的字符串写入到文本文件中
? ?// ? ? ? ? ? ? ? ?writer.write(s);
? ? ? ? ? ?}
? ? ? ?}catch(IOException e){
? ? ? ? ? ?e.printStackTrace();
? ? ? ?}
? ?}
? ?}
/**
?* 字符输出流
? ?*/
? ?public class FileCharOutputDemo {
? ?public static void main(String[] args) {
? ? ? ?try( Writer writer = new FileWriter("D:\\IoDemo\\text3.txt");){
? ? ? ? ? ?String s = "春风得意马蹄疾,一日看尽长安花";
? ? ? ? ? ?writer.write(s);
? ? ? ?} catch (IOException e) {
? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ?}
? ?}
? ?}
? ?字节转换流
? ?InputStreamReader:是字节流通向字符流的桥梁:他使用指定的charset读取字节并将其解码为字符。
/**
?* 字节转换输入流 ?字节转换为字符
? ?*/
? ?public class InputSteamReaderDemo {
? ?public static void main(String[] args) {
? ? ? ?try(InputStream inputStream = new FileInputStream("D:\\IoDemo\\filename.txt");
? ? ? ? ? ?//字符编码默认为utf-8
? ? ? ? ? ?InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"utf-8")){
? ? ? ? ? ?int k = 0;
? ? ? ? ? ?while((k = inputStreamReader.read())!=-1){
? ? ? ? ? ? ? ?System.out.print((char)k);
? ? ? ? ? ?}
? ? ? ?} catch (FileNotFoundException e) {
? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ?} catch (IOException e) {
? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ?}
? ?}
? ?}
(2)对象序列化 对象序列化的目标是将对象保存到磁盘中,或允许在网络中直接传输对象。对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,通过网络将这种二进制流传输到另一个网络节点。其他程序一旦获得了这种二进制流(无论是从磁盘中获取的,还是通过网络获取的),都可以将这种二进制流恢复成原来的Java对象。 序列化机制允许将实现序列化的Java对象转换成字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以备以后重新恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。对象的序列化(Serialize)指将一个Java对象写入IO流中,与此对应的是,对象的反序列化(Deserialize)则指从IO流中恢复该Java对象。 如果需要让某个对象支持序列化机制,则必须让它的类是可序列化的(继承serializable接口,该接口是一个标记接口,实现该接口无须实现任何方法,它只是表明该类的实例是可序列化的) 使用Serializable来实现序列化非常简单,主要让目标类实现Serializable标记接口即可,无须实现任何方法。 一旦某个类实现了Serializable接口,该类的对象就是可序列化的,程序可以通过如下两个步骤来序列化该对象。 ? 创建一个ObjectOutputStream 调用ObjectOutputStream对象的writeObject()方法输出可序列化对象 ? 注意: 1.如果修改类是仅修改了方法,则反序列化不受任何影响。不需要修改serialVersionUID的值 2.如果修改类时仅仅修改了静态变量或者transient实例变量,则反序列化不受任何影响。不需要修改serialVersionUID的值。 3.如果修改类时修改了非瞬时的实例变量,则可能导致序列化版本不兼容。如果对象流中的对象和新类中包含同名的实例变量,而实例变量类型不同,则反序列化失败,类定义应该更新serialVersionUID类变量的值。如果对象流中的对象比新类中包含更多的实例变量,则多出的实例变量值被忽略,序列化版本可以兼容,类定义可以不更新serialVersionUID的值。如果新类比对象流中的对象包含更多的实例变量,则序列化版本也可以兼容,类定义可以不更新serialVersionUID的值。但反序列化的对的新对象中多出的实例变量值都是null。
//继承Serializable可以被序列化
public class Student implements Serializable {
? ? //序列化版本号
? ? private static final Long serialVersionUID = 1L;
? ? private String name;
? ? //transient修饰的实例变量不能被序列化
? ? transient private Integer age;
? ? public Student(String name, Integer age) {
? ? ? ? this.name = name;
? ? ? ? this.age = age;
? ? }
? ?
? ? public String getName() {
? ? ? ? return name;
? ? }
? ?
? ? public void setName(String name) {
? ? ? ? this.name = name;
? ? }
? ?
? ? public Integer getAge() {
? ? ? ? return age;
? ? }
? ?
? ? public void setAge(Integer age) {
? ? ? ? this.age = age;
? ? }
? ?
? ? @Override
? ? public String toString() {
? ? ? ? return "Student{" +
? ? ? ? ? ? ? ? "name='" + name + '\'' +
? ? ? ? ? ? ? ? ", age=" + age +
? ? ? ? ? ? ? ? '}';
? ? }
}
/**
?* 序列化student对象
? ?*/
? ?public class ObjectOutputStreamDemo {
? ?public static void main(String[] args) {
? ? ? ?Student student = new Student("张三",18);
? ? ? ?try(OutputStream os = new FileOutputStream("D:\\IoDemo\\SerializableDemo.txt");
? ? ? ? ? ?ObjectOutputStream oos = new ObjectOutputStream(os)){
? ? ? ? ? ?//序列化student对象
? ? ? ? ? ?oos.writeObject(student);
? ? ? ?} catch (FileNotFoundException e) {
? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ?} catch (IOException e) {
? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ?}
? ?}
? ?}
/**
?* 反序列化
? ?*/
? ?public class ObjectInputStreamDemo {
? ?public static void main(String[] args) {
? ? ? ?try(InputStream is = new FileInputStream("D:\\IoDemo\\SerializableDemo.txt");
? ? ? ? ? ?ObjectInputStream ois = new ObjectInputStream(is)){
? ? ? ? ? ?//反序列化student对象
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?Student student = (Student)ois.readObject();
? ? ? ? ? ? ? ?System.out.println(student);
? ? ? ? ? ?}catch (ClassNotFoundException e) {
? ? ? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ? ? ?}catch (IOException e) {
? ? ? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ? ? ?}
? ? ? ?} catch (FileNotFoundException e) {
? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ?} catch (IOException e) {
? ? ? ? ? ?throw new RuntimeException(e);
? ? ? ?}
? ?}
? ?}
创建对象的方法有几种?
1、new关键字 2、Clone 浅克隆:浅克隆是将原对象中实例变量在堆内存中的内容完全复制,如果时基本类型,则复制值,如果是引用数据类型则复制其中的引用。有可能会出现克隆对象和被克隆对象中的某个实例变量指向同一对象。 深克隆:在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。 3、反序列化 4、反射