20145235 《Java程序设计》第6周学习总结

教材学习内容总结

10.1 InputStream与OutputStream

串流设计的概念

  • Java将输入/输出抽象化为串流,数据有来源及目的地,衔接两者的是串流对象。
  • 从应用程序角度来看,如果要将数据从来源取出,可以使用输入串流,如果要将数据写入目的地,可以使用输出串流。在Java中,输入串流代表对象为java.io.Inputstream实例,输出串流代表对象为java.io.OutputStream实例。
  • 在不使用InputStream与OutputStream时,必须使用close()方法关闭串流。由于InputStream与OutputStrem操作了java.io.Closeable接口,其父接口为java.lang.AutoCloseable接口。

串流继承架构

  1. System.in与System.out查看API文件的话,会发现它们分别是InputStream与PrintStream的实例,分别代表标准输入与标准输出。
  2. 可以使用System的setIn()方法指定InputStream实例,重新指定标准输入来源。标准输出可以重新导向至文档,只要执行程序时使用>将输出结果导向至指定文档。可以使用System的setOut()方法指定printStream实例,将结果输出至指定的目的地。
  3. FileInputStream是InputStream的子类,可以指定文件名创建实例,一旦创建文档就开启,接着就可用来读取数据。FileOutputStream是OutputStream的子类,可以指定文件名创建实例,一旦创建文档就开启,接着就可以用来写出数据。无论FileInputStream还是FileOutputStream,不使用时都要使用close()关闭文档。
  4. FileInputStream主要操作了InputStream的read()操作方法,使之可以从文档中读取数据,FileOutputStream主要操作了OutputStream的write()操作方法,使之可以写出数据至文档。
  5. ByteArryInputStream是InputStrteam的子类,可以指定byte数组创建实例,一旦创建就可将byte数组当做数据源进行读取。ByteArryOutputStream是OutputStream的子类,可以指定byte数组创建实例,一旦创建将byte数组当做目的地写出数据。
  6. ByteArryInputStream主要操作了InputStream的read()操作方法,使之可以从byte数组中读取数据,ByteArryOutputStream主要操作了OutputStream的write()操作方法,使之可以写出数据至byte数组。

串流处理装饰器

  • InputStream、OutStream提供串流基本操作,如果想要为输入/输出的数据做加工处理,则可以使用打包器类。常用的打包器具备缓冲区作用的BufferedOutputStream、BufferedInputStream,具备数据转换处理的DataInputStream、DataOutputStream,具备对象串行化能力的ObjectInputStream、ObjectOutputStream等。
  • BufferedInputStream与BufferedOutputStream主要在内部提供缓冲区功能,操作上与InputStream、OutputStream并没有太大区别。DataInputStream、DataOutputStream用来装饰InputStream、OutputStream,DataInputStream、DataOutputStream,提供读取、写入Java基本数据类型的方法,像是读写int、double、boolean等的方法。
  • -来看例子。下面的Member类可以调用save()储存Member实例本身的数据,文件名为Member的会员号码,调用Member.load()指定会员号码,则可以读取文档中的会员数据。代码运行结果如下:
package cc.openhome;

import java.io.*;

publicclass Member {
    privateStringnumber;
    privateString name;
    private int age;

    public Member(Stringnumber, String name, int age) {
        this.number = number;
        this.name = name;
        this.age = age;
    }

    publicString getNumber() {
        returnnumber;
    }

    publicvoid setNumber(Stringnumber) {
        this.number = number;
    }

    publicString getName() {
        return name;
    }

    publicvoid setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    publicvoid setAge(int age) {
        this.age = age;
    }
    
    @Override
    publicString toString() {
        returnString.format("(%s, %s, %d)", number, name, age);
    }
    
    publicvoid save() throws IOException {
        try(DataOutputStream output = 
                new DataOutputStream(new FileOutputStream(number))) {
            output.writeUTF(number);
            output.writeUTF(name);
            output.writeInt(age);
        } 
    }
    
    publicstatic Member load(Stringnumber) throws IOException {
        Member member;
        try(DataInputStream input = 
                new DataInputStream(new FileInputStream(number))) {
            member = new Member(
                    input.readUTF(), input.readUTF(), input.readInt());
        } 
        return member;
    }
}

  • ObjectInputStream提供readObject()方法将数据读入为对象,而ObjectOutputStream提供writeObject()方法将对象写至目的地。可以被这两个方法处理的对象,必须操作java.io.Serializable接口,这个接口并没有定义任何方法,只是作为标示之用,表示这个对象是可以串行化的。如下面范例Member2Demo的运行结果与MemberDemo的运行结果是一样的。运行截图如下:

10.2 字符处理类

 

  • 针对字符数据的读取,Java SE 提供了 java.io.Reader 类,其抽象化了字符数据读入的来源。
  • 针对字符数据的写入,Java SE 提供了 java.io.Writer 类,其抽象化了数据写出的目的地。
  • 使用 CharUtil.dump() 方法从来源读入字符数据、将字符数据写至目的地。代码如下:
    import java.io.*;
    
    public class CharUtil {
        public static void dump(Reader src, Writer dest) throws IOException {
            try(Reader input = src; Writer output = dest) {
                char[] data = new char[1024];
                int length;
                while((length = input.read(data)) != -1) {
                    output.write(data, 0, length);
                }
            }
        }
    }
  • read():每次从Reader 读入的数据,都会先置入 char 数组中,Reader 的 read() 方法,每次会尝试读入 char 数组长度的数据,并返回实际读入的字符数,只要不是-1,就表示读取到字符。
  • write():使用 write() 方法,指定要写出的 byte 数组、初始索引与数据长度。
  • 使用CharUtil.dump() 读入文档、转为字符串并显示在文本模式中。代码如下:
    package cc.openhome;
    
    import java.io.*;
    
    public class CharUtilDemo {
        public static void main(String[] args) throws IOException {
            FileReader reader = new FileReader(args[0]);
            StringWriter writer = new StringWriter();
            CharUtil.dump(reader, writer);
            System.out.println(writer.toString());
        }
    }
  • InputStreamReader 与 OutputStreamWriter:可对串流数据打包。
  • BufferedReader 与 BufferedWriter:可对 Reader、Writer 提供缓冲区作用,在处理字符输入输出时,对效率也会有所帮助。
  • BufferedReader 与 BufferedWriter:可对 Reader、Writer 提供缓冲区作用,在处理字符输入输出时,对效率也会有所帮助。

11.1线程

TortoiseHareRace2代码运行结果:


  • 从抽象观点来看,JVM是台虚拟计算机,只安装一颗称为主线程的CPU,可执行main()定义的执行流程。如果想要为JVM加装CPU,就是创建Thread实例,要启动额外CPU就是调用Thread实例的start()方法,额外CPU执行流程的进入点,可以定义在Runnale接口的run()方法中。
  • Daemon线程:主线程会从main()方法开始执行,直到main()方法结束后停止JVM。如果主线程中启动了额外线程,默认会等待被启动的所有线程都执行完run()方法才中止JVM。
  • 在所有的非Daemon线程都结束时,JVM自动就会中止。可以使用setDeamon()方法来设定一个线程是否为Daemon线程,可以使用isDaemon()方法来判断线程是否为Daemon线程。
  • Daemon线程,在所有的非Daemon线程都结束时,JVM就会终止。
  • 每个线程都属于某个线程群组,如果没有指定,则归入产生该子线程的线程群组,也可以自行指定线程群组,线程一旦归入某个群组,就无法再更换。ThreadGroup的某些方法,可以对群组中所有线程产生作用。如果想要一次取得群组中所有线程,可以使用enumerate()方法。activeCount()方法取得群组的线程数量。
  • 11.2 并行API

    • wait()、notify()、notifyAll()是object定义的方法,可以通过这3个方法控制线程释放对象的锁定,或者通知线程参与锁定竞争。
    • 若调用锁定对象的wait()方法,线程会释放对象锁定,并进入对象等待集合从而处于阻断状态,其他线程可以竞争对象锁定,取得锁定的线程可以执行synchronized范围的程序代码。
    • 放在等待集合的线程不会参与CPU排班,wait()可以指定等待时间,时间到之后线程会再次加入排班。
    • 如果指定时间0或不指定,则线程会持续等待,直到被中断(调用interrupt())或是告知(notify())可以参与排班。
    • LOCK:锁定lock对象,可以调用其lock方法,只有取得lock对象锁定的线程,才可以继续往后执行程序代码。解除锁定要调用unlock()。
    • Executor:将Runnable的指定与实际如何执行分离。

    其他(感悟、思考等,可选)

    这周突然开始想这么一个问题:“若干年后有人问我,‘你会什么?’。”是啊,我会什么?我会什么!我会什么呢?或许我会淡定的对他说:“我会敲代码!”。所以,希望从现在开始,我还来得及!看书说实话,我不怎么看的懂,从明天开始认真看视频,认真做好笔记。不负青春年华!

代码托管情况

 

原文地址:https://www.cnblogs.com/20145235litao/p/5375578.html