A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小石姐姐 于 2018-8-9 10:53 编辑



一、线程池

1、线程间通信
       多个线程在处理同一资源时即存在竞争也存在合作关系,多个线程并发执行时, 在默认情况下CPU是随机切换线程的。
等待唤醒机制
       wait/notify 就是线程间的一种协作机制, 用于解决线程间通信的问题
java.lang.Object类:
      
[Java] 纯文本查看 复制代码
Object obj= new Ojbect();

成员方法 (只能通过"锁对象"调用)
      
[Java] 纯文本查看 复制代码
void notify(): 随机唤醒在同一个锁对象上的某一个处于等待状态的线程
[font=微软雅黑][size=3]       [/size][/font]obj.notify();
[font=微软雅黑][size=3]       [/size][/font]void notifyAll(): 唤醒所有在同一个锁对象上处于等待状态的线程
[font=微软雅黑][size=3]       [/size][/font]obj.notifyAll();
[font=微软雅黑][size=3]       [/size][/font]void wait(): 让当前线程处于无限等待状态, 同时释放锁
[font=微软雅黑][size=3]       [/size][/font]obj.wait();

wait和notify/notifyAll的执行原理:
       执行wait,进入wait set中,处于“WAITING”,不去竞争锁程状态,等待“notify通知",被通知后也不能立即恢复执行(当初中断的地方是在同步块内, 而此刻它已经不持有锁, 所以它需要再次尝试去获取锁(很可能面临其它线程的竞争)),获取锁后恢复执行,获取失败进入锁阻塞。
调用 wait() 和 notify() 需要注意的细节:
       1. wait() 与 notify() 必须要由"同一个锁对象"调用
       2. wait() 与 notify() 是属于Object类的方法
       因为锁对象可以是任意对象, 而任意对象的所属类都是继承了Object类的
       3. wait() 与 notify() 必须要在"同步代码块"或者是"同步方法"中使用
       因为必须要通过锁对象调用这2个方法
线程状态图:

2、线程池
       线程池:一个容纳多个线程的容器
线程池的代码实现
       java.util.concurrent.Executors类: 线程池工厂类, 用于管理线程池
静态方法:
      
[Java] 纯文本查看 复制代码
static ExecutorService newFixedThreadPool(int nThreads): 创建固定数量线程的线程池(常用)
       java.util.concurrent.ExecutorService接口: 真正执行任务的线程池服务
成员方法:
      
[Java] 纯文本查看 复制代码
Future submit(Runnable task): 提交一个Runnable任务
       void shutdown(): 通知线程执行完任务后关闭. 如不调此方法, 则线程执行完任务后仍在运行以便重复使用
线程池的创建和使用步骤:
       1. 使用Executors的静态方法 newFixedThreadPool(int nThreads) 创建线程池ExecutorService
      
[Java] 纯文本查看 复制代码
ExecutorService executorService = Executors.newFixedThreadPool(2);

       2. 创建一个任务类, 实现Runnable接口, 重写run()方法
       3. 调用ExecutorService对象的 submit(Runnable task) 方法, 传递任务给线程池, 执行任务
      
[Java] 纯文本查看 复制代码
executorService.submit(new RunnableImpl());

       4. 调用ExecutorService对象的 shutdown() 方法, 销毁线程池 (不建议执行)
      
[Java] 纯文本查看 复制代码
executorService.shutdown();



二、Lambda表达式
1、Lambda表达式的3个部分:
       1. 一些参数 ()
       接口中抽象方法的参数列表. 没参数就空着; 有参数就写, 多个参数用逗号分隔
       2. 一个箭头 ->
       将参数传递给方法体
       3. 一段代码 {}
       重写接口抽象方法的方法体
Lambda标准格式:
       // 写成一行
(参数列表) -> {一些重写方法的代码}
       // 写成多行
(参数列表) -> {
       一些重写方法的代码
}
2、 函数式编程和面向对象方式的对比
面向对象方式的代码
      
[Java] 纯文本查看 复制代码
new Thread(new Runnable() {
@Override
       public void run() {
       System.out.println(Thread.currentThread().getName() + "新线程创建了");
       }
       }).start();
函数式编程的代码
      
[AppleScript] 纯文本查看 复制代码
new Thread(()-> {
       System.out.println(Thread.currentThread().getName() + "新线程创建了");
[font=微软雅黑][size=3]       [/size][/font]}
[font=微软雅黑][size=3]       [/size][/font]).start();
案例:厨师喊吃饭
[Java] 纯文本查看 复制代码
/*
       厨师接口
*/
       public interface Cook {
       void makeFood();
}
/*

Lambda标准格式: 厨师做饭(无参无返回值)
[Java] 纯文本查看 复制代码
*/
       public class Test {
       public static void main(String[] args) {
// Lambda表达式方式
       invodeCook(()->{
       System.out.println("吃饭啦");
       });
       }
       // 调用厨师做饭
       public static void invodeCook(Cook cook) {
       cook.makeFood();
       }
       }

案例: 数组排序  匿名内部类和Lambda表达式
匿名内部类
      
[Java] 纯文本查看 复制代码
 // Arrays.sort(persons, new Comparator<Person>() {
       // @Override
       // public int compare(Person o1, Person o2) {
       // return o1.getAge() - o2.getAge();
       // }
       // });
Lambda表达式
      
[Java] 纯文本查看 复制代码
Arrays.sort(persons, (Person o1, Person o2) -> {
       return o1.getAge() - o2.getAge();
       });
3、Lambda省略格式和使用前提
       函数式接口"有且仅有一个抽象方法"
       但函数式接口对于哪些方法算作抽象方法有特殊规定:
1>有方法体的方法"不算作"抽象方法, 如默认方法, 静态方法, 私有方法
2> 抽象方法与java.lang.Object类中的方法定义相同的, 也"不算作"抽象方法
       因为任何实现本接口的实现类, 都会直接或间接继承java.lang.Object类的public的方法, 所以在创建
       实现类时其实不用重写该抽象方法, 也就不算作抽象方法
总结:
Lambda表达式的使用前提:
       1. Lambda只能用于接口, 且"接口中有且仅有一个抽象方法"(也称为"函数式接口")       普通类, 抽象类不能用
       2. 使用Lambda必须具有上下文推断
方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例
(简而言之: 作为参数类型的接口, 必须是函数式接口)
问题分析:
需求:10个顾客,2张餐桌,2个服务员.同时只能2人进餐.
      
[Java] 纯文本查看 复制代码
 public class Myrunnable implements Runnable {
      static Object obj=new Object();
    @Override
       public void run() {
        // Object obj=new Object();
        synchronized (obj){
            System.out.println(Thread.currentThread().getName()+"服务员开始为顾客点菜.......顾客开始用餐");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            System.out.println("顾客食用完毕"+Thread.currentThread().getName()+"服务员收拾桌子");
        }
       }
       }
实现类
      
[Java] 纯文本查看 复制代码
public class Demo00 {
       public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 10; i++) {
            es.submit(new Myrunnable());
        }
        es.shutdown();
该需求不需要锁对象
       原因:买票案例中private int booking=100;是成员变量,是各线程共有的;
       而本案例中顾客只在方法内体现,不被共享,所以不用锁对象;
如果用锁对象该案例应如何编写程序?
      
[Java] 纯文本查看 复制代码
 ExecutorService es = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 10; i++) {
            es.submit(new Myrunnable());

       此代码无法实现lock;
       因为每次new Myrunnable()便进行一次new Object(),synchronized (obj)进行中的锁对象每次都不相同;static Object obj=new Object();应为静态成员对象。
三、递归
1、递归概括
       方法内部调用方法自己 (所以必须定义方法);
递归的使用前提:
       调用方法时, 方法的主体不变, 但每次传递的参数值不同, 可以使用递归;
递归时的注意事项:
       1> 递归要有限定条件(出口), 保证递归能够停止(就是在某种情况下方法不再调用自己), 否则会栈内存溢出
       2> 递归次数不能太多, 否则会栈内存溢出
       3>构造方法不能递归
2、案例:
       计算1~n的和

      
[Java] 纯文本查看 复制代码
public class Test {
       public static void main(String[] args) {
       int sum1 = sum(3);
       System.out.println(sum1);
       }
       public static int sum(int ) {
// 出口
       if (n == 1) {
       return 1; 
       }
       return   n+ sum(n- 1);
       }}
四、IO流
1、File类
1.1  File类的静态成员变量
       java.io.File类: 文件和目录的路径名的抽象表现形式, 主要用于文件和目录的创建, 查找和删除等操作
静态成员变量
      
[Java] 纯文本查看 复制代码
static String pathSeparator: 路径分隔符的字符串形式
       static char pathSeparatorChar: 路径分隔符的char形式
       Windows系统是 分号;
       Linux系统是 冒号:
      
[Java] 纯文本查看 复制代码
static String separator: 文件名称分隔符的字符串形式
       static char separatorChar: 文件名称分隔符的char形式
       Window系统是 反斜杠\
       Linux系统是 正斜杠/
1.2  绝对路径和相对路径
绝对路径:
       以盘符开始的路径
       如: "D:\\a\\hi.txt"
相对路径:
       不以盘符开始的简化路径. 相对于项目的根目录
       如: "a\\1.mp3", "123.txt"
注意事项:
       1.路径不区分大小写 (在Windows系统中不区分大小写, Linux, Mac区分)
       2.路径一般写成字符串, 而字符串中一个\是转义, 所以要写两个\\(正则表达式)
1.3  File类: 构造、获取、判断方法
构造
      
[Java] 纯文本查看 复制代码
File File(String pathname): 根据 路径字符串 封装一个File对象
       File f1 = new File("z:\\z.txt");
       File File(String parent, String child): 根据 父路径字符串 和 子路径字符串 封装File对象
       File f2 = new File("a\\", "a.txt");
       File File(File parent, String child): 根据 父路径的File对象 和 子路径 封装File对象
       File f3 = new File(new File("d:\\"), "d.txt");
获取
      
[Java] 纯文本查看 复制代码
String getAbsolutePath(): 返回此File的绝对路径名字符串
       String s=f3.getAbsolutePath();
       String getPath(): 获取File对象的封装路径 (创建对象时传入的路径)
       String s=f3.getPath();
       String getName(): 获取File对象的文件名或目录名
       String s=f3.getName();
       long length(): 获取File表示的文件大小的字节数 (不能获取目录的大小)
       long l=f3.length();
判断
      
[Java] 纯文本查看 复制代码
 boolean exists(): 判断File对象代表的文件或目录是否实际存在
       boolean b=f3.exists();
       boolean isDirectory(): 判断File表示的是否为目录
       boolean b=f3.isDirectory();
       boolean isFile(): 判断File表示的是否为文件
       boolean b=f3.isFile();
1.4  File类: 创建、删除、遍历方法
创建、删除
      
[Java] 纯文本查看 复制代码
 boolean createNewFile(): 当文件不存在时, 创建一个新的空文件
       File fileB = new File("day08\\a\\b\\b.txt");
       fileB.createNewFile();
       boolean delete(): 删除由此File表示的文件或目录. (删除目录时必须是空目录)
       fileB. delete();
       boolean mkdir(): 创建File表示的目录
       File dirA = new File("day08\\a");
       dirA.mkdir();
       boolean mkdirs(): 创建File表示的多级目录
       File dirAB = new File("day08\\a\\b");
       dirAB.mkdirs();
注意事项:
       重要英文单词的含义: (起变量名时会用到)
       file: 文件
       directory: 目录
       path: 路径
遍历
      
[Java] 纯文本查看 复制代码
String[] list(): 获取当前File目录下的所有子文件或目录的名字数组
       File[] files = module.listFiles();
       File[] listFiles(): 获取当前File目录中的所有子文件或目录的File对象数组
       String[] list = module.list();
1.5  FileFilter文件过滤器的原理和使用
java.io.File类: Filter过滤器
      
[Java] 纯文本查看 复制代码
File[] listFiles(FileFilter filter): 通过File对象过滤, 返回文件过滤器过滤后的File对象数组
       File[] listFiles(FilenameFilter filter): 通过File对象的文件名过滤, 返回文件过滤器过滤后的File对象数组
java.io.FileFilter接口: 用于File对象的过滤器
      
[Java] 纯文本查看 复制代码
boolean accept(File pathName): true则会将参数的File对象加入返回的File[], false则不加入
       java.io.FilenameFilter接口:
       boolean accept(File dir, String name): true则会将参数的File对象加入返回的File[], false则不加入


综合案例
补充String类中的方法:
      
[AppleScript] 纯文本查看 复制代码
boolean endsWith(String suffix): 判断字符串是否以指定的字符串结尾
       String toLowerCase(): 将字符串转为小写字母
需求: 打印当前模块中的.java文件 (包含子目录)
      
[Java] 纯文本查看 复制代码
public class Test {
       public static void main(String[] args) {
       print(new File("day08"));
       }
       public static void print(File dir) {
// 获取当前目录中的文件, 使用过滤器
       /*File[] files = dir.listFiles(new FilenameFilter() {
       @Override
       public boolean accept(File dir, String name) {
       return  new File(dir, name).isDirectory() ||
       name.toLowerCase().endsWith(".java");
       }
       });*/
[Java] 纯文本查看 复制代码
// 使用Lambda表达式简化
       File[] files = dir.listFiles((d, name) -> new File(d, name).isDirectory() ||
       name.toLowerCase().endsWith(".java"));
       for (File file : files) {
       if (file.isFile()) {
       System.out.println(file);
       } else if (file.isDirectory()) {
       print(file);
       }

错题分析:
      
[Java] 纯文本查看 复制代码
 public static void main(String[] args) {
        List<File> list=new ArrayList<>();
        File f=new File("F:\\IdeaProjects");
       list= getlist(f);
        for (File f1 : list) {
            System.out.println(f1);
        }
        }
        public static List<File> getlist(File f) {
        List<File> list=new ArrayList<>();
        File[] files = f.listFiles();
        for (File fi : files) {
            if(fi.isDirectory()){
                list.add(fi);
  (getlist(fi));
            }if(fi.isFile()){
                list.add(fi);
            }
        }
        return list;
    }
}
       标红处方法被调用了,但值未返回
         正确代码: list.addAll(getlist(fi));
2、IO流的分类:
       字节流 (读写字节: byte, 可以读写所有类型的文件, 包括视频, 图片, 音频, 文本等)
       字节输入流: java.io.InputStream 抽象类
       字节输出流: java.io.OutputStream 抽象类
       字符流 (读写字符: char, String, 只能读写文本文件)
       字符输入流: java.io.Reader 抽象类
       字符输出流: java.io.Writer 抽象类

2.1  字节流  
1>  FileOutputStream和FileInputStream
FileOutputStream
java.io.OutputStream抽象类: 字节输出流 (顶层类)
成员方法
       void close() :释放资源
写字节的成员方法
      
[Java] 纯文本查看 复制代码
abstract void write(int b): 一次写一个字节 (参数是int是为了代码中写表示byte的整数方便不用强转)
       fos.write(97);
       void write(byte[] b): 一次写一个字节数组
       byte[] bytes={1,2,3,}
       fos.write(bytes);
       void write(byte[] b, int off, int len): 一次写一个字节数组的一部分
       byte[] bytes={1,2,3,}
       fos.write(bytes,0,2);
java.io.FileOutputStream类: 文件字节输出流 (向文件写数据)
写多个字节时:
       如果第一个字节是正数中的 0~127, 则记事本会查询 ASCII码表 显示字符
       如果第一个字节是负数中的:-128~-1, 则记事本会查询 GBK码表 显示字符.(将两个连续的byte组合为一个中文)
构造方法
      
[Java] 纯文本查看 复制代码
FileOutputStream(String name): 通过文件路径创建文件字节输出流
       FileOutputStream fos = new FileOutputStream("day09\\testOutputStream1.txt");
       FileOutputStream(File file): 通过File对象创建文件字节输出流
字节输出流: 续写操作
java.io.FileOutputStream类: 文件字节输出流
带有 续写 功能的构造方法, 不会清空文件
      
[Java] 纯文本查看 复制代码
 FileOutputStream(String name, boolean append): 通过文件路径创建文件字节输出流, true可以续写
       FileOutputStream(File file, boolean append): 通过File对象创建文件字节输出流, true可以续写
换行符:
       Windows系统: "\r\n"
       Linux系统: "\n"
       MacOS系统: "\r"
       FileInputStream
java.io.InputStream抽象类: 字节输入流 (顶层类)
常用成员方法
void close(): 释放资源
读数据的方法
      
[Java] 纯文本查看 复制代码
int read(): 一次读一个字节
       int by; // int变量用来存储每次读到的数据
       while ((by = fis.read()) != -1) {
       System.out.print((char)by); // 不要换行, 文件中自带换行的byte
       }
       读到文件末尾返回-1 (返回int也是为了代码编写方便)
      
[Java] 纯文本查看 复制代码
int read(byte[] b): 一次读一个字节数组

       读到的字节存放在参数中的字节数组中, 返回int值是本次读到的字节的个数. 读到文件末尾返回-1
      
[Java] 纯文本查看 复制代码
 byte[] bytes = new byte[1024]; // 定义字节数组, 用于保存每次读取到的数据
       while ((len = fis.read(bytes)) != -1) {
       String s = new String(bytes, 0, len); // 将读取到的字节转换为字符串, 读到多少个就转换多少个
       System.out.print(s);
       }
       while ((len = fis.read(bytes)) != -1) {
// 将读取到的字节数组转换为String, 读到多少就转换多少, 不要全转
       String s = new String(bytes, 0, len);

java.io.FileInputStream类: 文件字节输入流构造方法
      
[Java] 纯文本查看 复制代码
 FileInputStream(String name): 使用文件路径创建文件字节输入流
       FileInputStream(File file): 使用File对象创建文件字节输入流
2>  字节缓冲流 BufferedInputStream(InputStream in)和BufferedOutputStream(OutputStream out)
构造方法:
      
[Java] 纯文本查看 复制代码
public BufferedInputStream(InputStream in) :创建一个 新的缓冲输入流。
       BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt"));
       public BufferedOutputStream(OutputStream out) : 创建一个新的缓冲输出流。
       BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
3>  对象序列化流: ObjectOutputStream和ObjectInputStream
对象(反)序列化流: ObjectOutputStream
java.io.ObjectOutputStream类: 对象字节输出流
构造方法
      
[Java] 纯文本查看 复制代码
ObjectOutputStream(OutputStream out)

特有成员方法
      
[Java] 纯文本查看 复制代码
void writeObject(Object obj): 将对象写出

创建对象输出流
      
[Java] 纯文本查看 复制代码
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.txt"));

写对象
      
[AppleScript] 纯文本查看 复制代码
 Student s = new Student("小美女", 18);
       oos.writeObject(s);
释放资源
      
[Java] 纯文本查看 复制代码
 oos.close();

注意:
       被读写的对象的类, 必须实现 java.io.Serializable 接口, 否则会抛出 NotSerializableException
       该类的所有属性也都必须是可序列化的. (实现 java.io.Serializable 接口)
       如果某个属性不需要序列化, 则需要用 transient 修饰为瞬态的
       如果要将集合序列化, 那么集合中存储的对象也必须是可序列化的
对象反序列化流: ObjectInputStream
       java.io.ObjectInputStream类: 对象字节输入流
构造方法
      
[Java] 纯文本查看 复制代码
ObjectInputStream(InputStream in)

特有成员方法
      
[Java] 纯文本查看 复制代码
 Object readObject(): 读取对象

创建对象输入流
      
[Java] 纯文本查看 复制代码
ObjectInputStream oos = new ObjectInputStream(new FileInputStream("student.txt"));

读对象
      
[Java] 纯文本查看 复制代码
 Object o = oos.readObject();
       Student s = (Student)o;
       System.out.println(s);
释放资源
       oos.close();
transient瞬态关键字: 避免属性序列化
       static 修饰的成员变量属于类不属于对象, 所以不能序列化
       transient 修饰的成员变量, 不能被序列化
       如果对象的某个属性不希望被序列化, 可以使用transient修饰, 这样就不会被对象流写到文件中
4>  打印流PrintStream
PrintStream特点:
       1. 只有输出流, 没有输入流
       2. PrintStream永远不会抛出IOException
       3. 有特殊方法 print(), println(), 可以输出任意类型的值
java.io.PrintStream类: 字节打印流
构造方法
      
[Java] 纯文本查看 复制代码
PrintStream(File file): 创建字节打印流, 输出到一个文件
       PrintStream(OutputStream out): 创建字节打印流, 输出到一个字节输出流
       PrintStream(String fileName): 创建字节打印流, 输出到一个文件路径
注意事项:
       如果用 write() 方法, 会查编码表
       如果用 print(), println(), 则原样输出
java.lang.System类:
静态方法
      
[Java] 纯文本查看 复制代码
static void setOut(PrintStream out): 设置System.out的输出目的地为参数的打印流

2.2  字符流
1>  字符流 FileReader和FileWriter
FileReader(只能读写文本文件  char,String)
java.io.Reader抽象类: 字符输入流 (顶层)
常用成员方法
      
[Java] 纯文本查看 复制代码
void close() :关闭此流并释放与此流相关联的任何系统资源
[font=微软雅黑][size=3]读[/size][/font]
       int read(): 一次读一个字符char, 返回读到的字符.
       读到文件末尾返回-1 (返回int为了代码编写方便)
       int read(char[] cbuf): 一次读取一个字符数组char[]
       返回读取的字符个数. 读到文件末尾返回-1
java.io.FileReader类: 文件字符输入流
构造方法
      
[Java] 纯文本查看 复制代码
FileReader(File file): 根据File对象创建文件字符输入流
       FileReader(String fileName): 根据File对象创建文件字符输入流
FileWriter
java.io.Writer抽象类: 字符输出流 (顶层类)
常用成员方法
      
[Java] 纯文本查看 复制代码
abstract void close(): 刷新缓冲区并释放资源
       abstract void flush() :刷新缓冲区

      
[Java] 纯文本查看 复制代码
void write(int c): 写一个字符 (int类型为了代码编写方便)
       void write(char[] cbuf): 写一个字符数组
       abstract void write(char[] b, int off, int len): 写一个字符数组的一部分
       void write(String str): 写一个字符串
       void write(String str, int off, int len): 写一个字符串的一部分
注意: write()方法只是将数据写到内存缓冲区, 最后必须调用flush()或close()才能将数据真正写入磁盘
       flush():缓存作用,flush()后可以继续编写;可省略
       close():缓存且释放资源,close()后不可继续写;不可省略
作用:
       1. 创建FileWriter对象
       2. 根据构造方法中的路径, 在磁盘上创建文件 ("如果文件已存在, 则清空文件内容")
       3. 将FileWriter对象指向磁盘上的文件
写的其他方法:
      
[Java] 纯文本查看 复制代码
void write(char[] cbuf): 写一个字符数组
       abstract void write(char[] b, int off, int len): 写一个字符数组的一部分
       void write(String str): 写一个字符串
       void write(String str, int off, int len): 写一个字符串的一部分
2>  字符缓冲流BufferedReader(Reader in)和 BufferedWriter(Writer out)
构造方法:
      
[Java] 纯文本查看 复制代码
public BufferedReader(Reader in) :创建一个 新的缓冲输入流。
       BufferedReader br = new BufferedReader(new FileReader("br.txt"));
       public BufferedWriter(Writer out) : 创建一个新的缓冲输出流。
       BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
特有方法:
      
[Java] 纯文本查看 复制代码
BufferedReader: public String readLine() : 读一行文字。
        while ((line = br.readLine())!=null) {
            System.out.print(line);
            System.out.println("‐‐‐‐‐‐");
       BufferedWriter: public void newLine() : 写一行行分隔符,由系统属性定义符号。
[Java] 纯文本查看 复制代码
// 写出数据  
        bw.write("黑马");
// 写出换行  
        bw.newLine();
        bw.write("程序");
        bw.newLine();
        bw.write("员");

3>  转换流InputStreamReader和OutputStreamWriter
InputStreamReader类
      
[Java] 纯文本查看 复制代码
 InputStreamReader(InputStream in) : 创建一个使用默认字符集的字符流。
       InputStreamReader isr = new InputStreamReader(new FileInputStream("in.txt"));
       InputStreamReader(InputStream in, String charsetName) : 创建一个指定字符集的字符流。
       InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");
OutputStreamWriter类
      
[Java] 纯文本查看 复制代码
 OutputStreamWriter(OutputStream in) : 创建一个使用默认字符集的字符流。
       OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream("out.txt"));
       OutputStreamWriter(OutputStream in, String charsetName) : 创建一个指定字符集的字符流。
       OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("out.txt") , "GBK");

2.3  IO异常处理
IO异常处理处理方法有2种:
       1,抛出()声明问题:如果报错,后面所有代码将无法执行
       2.使用try catch
      
[Java] 纯文本查看 复制代码
FileWriter fw = null;
       try {
// 流对象初始化
       fw = new FileWriter("day09\\testFileWriter2.txt", true); // 带有续写
 // IO操作
// 循环写5次
       for (int i = 0; i < 5; i++) {
// 写入内容和换行
       fw.write("HelloWorld\r\n");
       }
       } catch (IOException e) {
       e.printStackTrace();
       } finally {
// 当流对象不为null时释放资源
       if (fw != null) {
// 释放资源
       try {
       fw.close();
       } catch (IOException e) {
       e.printStackTrace();
       }finally{
       if(fw!=null){
       fw.close()
       }}}}
2.4  InvalidClassException异常: 原因和解决方案
serialVersionUID序列号的作用:
       序列化操作时, 会根据类生成一个默认的 serialVersionUID 属性, 写入到文件中.
       该版本号是根据类中成员计算出来的一个数值. 当类的成员发生改变时, 序列版本号也会发生变化
       当代码中的类和读取的对象序列版本号不一致时, 就会抛出InvalidClassException
       为了避免这种问题, 我们可以手动写死这个序列号, 这样无论成员如何变化, 序列版本号都是一样的
解决方法: IDEA设置生成序列版本号:
       在IDER中实行如下操作
       Setting ->  Editor ->  Inspections ->  Java ->  Serialization issues -> 勾选 Serializable class without'serialVersionUID'
       然后在类名上按 Alt + Enter 提示就会有 Add 'serialVersionID' field
2.5  字符编码和字符集
1>  编码表: 字符和二进制数字的对应规则
字符集和编码表: 字符集包含编码表
ASCII字符集
       ASCII编码表
       ISO-8859-1字符集:
       Latin-1: 拉丁字符. 没有中文. 每个字符由1个byte组成
GB字符集
       GB2312编码表: 每个字符由2个byte组成
       GBK编码表: 每个字符由2个byte组成
       GB18030编码表: 每个字符由1, 2, 4个byte组成
Unicode
       UTF-8: ASCII字符占1个byte, 拉丁字符占2个byte, 中文占3个byte, Unicode辅助字符占4个byte
       UTF-16
       UTF-32
ANSI: 表示使用系统默认编码表
2>  乱码原因: 读写编码不一致
       GBK文件中存储的是"你好"在GBK中对应的byte
       而IDEA中使用FileReader读取文件时, 是将byte按照UTF-8编码表查找字符, 结果找不到, 就显示了问号






0 个回复

您需要登录后才可以回帖 登录 | 加入黑马