小白学习Java第十八天

复习

1.字符输入流

作用:用来读取纯文本数据。
Reader
FileReader
read()/read(char[] ch)

2.字符缓冲流
BufferedReader : readLine()
BufferedWriter : newLine()

3.转换流

也是字符流,也是Reader和Writer子类。
InputStreamReader : 将字节输入流转为字符输入流,并且可以指定编码格式
OutputStreamWriter :将字符输出流转为字节输出流,并且可以指定编码格式

4.对象序列化

基本类型、包装类对象、String、集合对象…都可以进行序列化(持久化存储,按照字节序列的方式)
反序列化,即将序列化的数据进行读取,注意一定要按照顺序。否则容易出现:EOFException
ObjectOutputStream :
writeObject()
ObjectInputStream:
readObject()
实际序列化的是对象的属性信息,如果某个属性不想要进行序列化,使用关键字transient来修饰。
某个对象想要序列化一定要实现:Serializable改变
类会有一个 serialVersionUID 版本号生成,默认是随机值,类中内容发生改变这个版本号也会改变
序列化和反序列化都想要成功,看到的需要是同一个版本号,可以在定义类时,确定版本号始终是同一个。

5.打印流(了解)

PrintStream :字节打印流,是OutputStream的子类
PrintWriter :字符打印流,是Writer的子类
这两个对象用来大致相同,类中扩展提供了大量的print/println方法,可以向目的地写出任意类型的数据。

集合框架

Collection : 单列集合
—List : 有序可重复
—ArrayList: 数组算法, 适合做查找
—LinkedList: 双向链接列表 , 适合做增删操作,头尾有特有方法,get、remove、add
—Vector :数组算法,jdk1.0时期,线程安全对象
—Set : 无序不可重复
—HashSet : 哈希表算法, 依赖于:hashCode、equals
—LinkedHashSet: 哈希表+链接列表实现, 特点:有序不可重复
—TreeSet: 二叉树算法,元素唯一要排序
自然顺序排序:Comparable
比较器排序: Comparator
add() size() iterator()/for-each…

Map : 双列集合
—HashMap : key,采用哈希表算法
—LinkedHashMap :key, 哈希表+链接列表实现, 特点:有序不可重复
—TreeMap : key,二叉树算法,唯一排序
—Hashtable: 线程安全对象,jdk1.0,key,哈希表算法
put() size() keySet/entrySet get(key)…

IO流技术:
读写数据,即数据保存和获取。
字节流:
InputStream
—FileInputStream
—BufferedInputStream
read()
OutputStream
—FileOutputStream
—BufferedOutputStream
write()
字符流:
Reader
—FileReader
—BufferedReader readLine()
read()
Writer
—FileWriter
—BufferedWriter newLine()
writer()
flush()
本质: 字节流+编码表
其他流:
转换流 :InputStreamReader和OutputStreamWriter , 可以指定编码格式
打印流 :PrintStream/PrintWriter print/println方法
对象流 :ObjectInputStream ObjectOutputStream , 对象序列化和反序列化, writeObject 、readObject
Properties: 集合map和IO流的结合产物。
存储键值对,可以将键值对保存到流中,也可以将流中的键值对存储到Properties中。

课程

一. Properties

(一)Properties概述

  1. Properties:表示一个持久的属性集,是一个Map体系的集合类,是Hashtable的子类,所以可以当做普通的Map来使用,属性列表中的每个键及其对应的值都是一个字符串,因此不需要写泛型

  2. Properties一般是用于进行配置文件的读写
    配置文件中,一般都是键值对的关系(都是String类型)进行存储, 因此Properties中默认存储的键值对类型也是<String,String>

  3. 编写配置文件时,注释使用#表示
    #userName 表示用户姓名
    userName = mysql
    password = 88888

  4. 构造方法: 直接使用空参数的构造即可

(二)Properties集合常用方法

  1. put(key k,Value v): 将参数中的键值对存储在Properties集合中,继承自父接口中的方法
  2. setProperty(String key, String value) : 将键值对映射关系添加到集合中,键和值都是String类型,key值不重复,如果重复,表示value值修改
  3. getProperty(String key): 通过指定key值获取到对应value
  4. stringPropertyNames() :将Properties集合中所有的key值获取到,放置到Set集合中
import java.util.Properties;
import java.util.Set;

public class Demo1 {
    public static void main(String[] args) {
        //创建属性集对象
        Properties prop = new Properties();
        //存储key-value
        prop.setProperty("name","zhangsan");
        prop.setProperty("age","18");
        //根据key获取value
        String name = prop.getProperty("name");
        System.out.println(name);
        //遍历
        Set<String> keys = prop.stringPropertyNames();
        for (String key : keys){
            System.out.println(key+"...."+prop.getProperty(key));
        }



        /*prop.put("name","zhangsan");
        Set<Object> keys = prop.keySet();
        for (Object key : keys){
            System.out.println(key+"..."+prop.get(key));
        }
        //这种方式,是使用map中的方法操作的,不建议,因为类型都是Object类型。*/
    }
}

/*
* Properties:
*    property这个单词的复数形式,属性的意思。
*    作用:用于持久化存储属性集合的对象,即存储键值对的对象,其实是Map的实现类,具体是Hashtable的子类对象。
*    因此可以使用map中的方法操作该对象,但是Properties存储的键值对的数据类型是固定的,都是字符串,因此不建议使用map中的方法操作。
*    可以从流中读取数据,也可以将数据存储到流中。
* */

(三)Properties和IO流结合使用

  1. load(InputStream inStream) : 从输入字节流读取属性列表(键和元素对)
  2. load(Reader read): 从输入字符流读取属性列表(键和元素对)
  3. store(OutputStream out, String comments) : 使用字节的输出流,将Properties集合中的键值对元素同步到对应的文件中,comments 就是针对于本次修改的描述
  4. store(Writer out, String comments) : 使用字符的输出流,将Properties集合中的键值对元素同步到对应的文件中,comments 就是针对于本次修改的描述

案例: 利用Properties读取配置文件数据并且修改配置文件内容

  1. 先创建一个配置文件, config.properties
  2. 配置文件的书写格式(正常的配置文件中,数据通常都是英文的)
    userName=zhangsan
    age=25
  3. 通过load方法,读取配置文件中的内容到Properties集合
  4. 修改配置文件的内容 : 将姓名数据修改为lisi
    setProperty(String key, String value) : 修改Properties集合中键值对数据
    store(输出流,”修改原因”) : 将Properties集合中键值对同步到配置文件中
import java.io.*;
import java.util.Properties;

public class Demo2 {
    public static void main(String[] args) throws IOException {
        //创建属性集对象
        Properties prop = new Properties();
        /*//存储key-value
        prop.setProperty("name","zhangsan");
        prop.setProperty("age","18");
        prop.setProperty("gender","男");

        //存储到流中
        prop.store(new FileOutputStream("prop.properties"),"这是对象信息");*/

        //读取流中的数据,存储到prop中
        prop.load(new FileInputStream("prop.properties"));
        prop.setProperty("name","lisi");

        //修改后,再次存储
        prop.store(new FileWriter("prop.properties"),"");
    }
}

/*
* store(OutputStream/Writer , String  注释) : 将键值对存储到流中
* load(InputStream/Reader) : 将键值对格式的数据源读取到properties对象中
* */

二. 多线程

(一) 线程的相关概念

1.1进程和线程的区别

  1. 进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。

  2. 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
    简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

在这里插入图片描述

在这里插入图片描述

1.2 并行和并发

  1. 并行: 指两个或多个事件在同一个时间段内发生
  2. 并行:指两个或多个事件在同一时刻发生(同时发生)

在这里插入图片描述

public class Demo3 {
}
/*
* 多线程:
*   1.线程、进程
*      进程: 正在运行中的程序
*            资源: 内存  + CPU
*            CPU: 在某一时刻只能只能一个程序。
*                 是因为在做着高速的切换,速度非常快,我们的眼睛观察不到。
*     线程: 是进程中的内容,一个进程中可以有多个执行顺序(单元),其中的一个单元叫做线程。
*           线程是可以独立运行的代码段。进程中至少一个线程。
*
*     目前写的java程序,jvm只调用main方法,因此当前的进程中的线程就是main方法中的代码---主线程
*     创建子线程,在主线程中创建子线程。
*
*   2.并行、并发
*      并行: 多个任务同时发起,在某一时刻每个任务都在执行。  (多个cpu)
*      并发: 多个任务同时发起,在某一时刻只有一个任务在执行。(单个cpu)
* */

(二) 多线程的实现方式

2.1多线程实现的第一种方式:继承方式
  1. 继承Thread类

  2. 步骤:

    1. 定义一个类,继承Thread类
    2. 重写自定义类中的run方法,用于定义新线程要运行的内容
    3. 创建自定义类型的对象
    4. 调用线程启动的方法:start方法
      使该线程开始执行;Java 虚拟机调用该线程的 run 方法
  3. 图示:

在这里插入图片描述

4.使用匿名内部类实现多线程

public class Demo4 {
    public static void main(String[] args) {
        MyThread my = new MyThread();
        my.start(); //启动线程,自动调用run方法

        for(int i = 0; i < 100; i++){
            System.out.println("主线程------------------------------"+i);
        }

        //匿名内部类形式
        new  Thread(){
            public  void  run(){
                for (int i = 0; i < 100; i++){
                    System.out.println("子线程------"+i);
                }
            }
        }.start();
    }
}
/*
* 创建线程:
*    1.继承方式
*      java语言是面向对象的思想,任何事物都可以用对象来描述。
*      因此线程这类事物也有对象来藐视----java.lang.Thread类。
*    步骤:
*      1.定义类继承Thread类
*      2.重写run方法----线程要执行的代码
*      3.创建线程对象--创建子类对象
*      4.调用start方法,启动线程
*
*   原理:
*      thead类实现了Runnable接口,重写run方法,run方法就是线程任务代码的封装
*      调用start方法,启动线程,自动调用run方法。
*      跟踪原码:
*        start--->start0(本地方法,回调run方法)--->run(),我们自己封装的。
*   好处:
*       代码简单,易懂。
*   弊端:
*       耦合度增强 ,使用继承前提是符合 is-->a , 由于java是单继承也不能在继承其他类。
*
*  总结:继承方式在实际开发中不建议使用。
* */

class  MyThread  extends  Thread{
    @Override
    public  void  run(){
        for (int i = 0; i < 100; i++){
            System.out.println("子线程------"+i);
        }
    }
}
2.2多线程实现的第二种方式:实现方式
  1. 实现Runnable接口:Runnable接口的实现类对象,表示一个具体的任务,将来创建一个线程对象之后,让线程执行这个任务

  2. 步骤:
    1)定义一个任务类,实现Runnable接口
    2)重写任务类中的run方法,用于定义任务的内容
    3)创建任务类对象,表示任务
    4)创建一个Thread类型的对象,将任务对象作为构造参数传递,用于执行任务类对象
    Thread(Runnable able);
    5)调用线程对象的start方法,开启新线程
    调用的就是Thread类构造方法中传递的able线程任务中的run方法

  3. 使用匿名内部类实现多线程

public class Demo5 {
    public static void main(String[] args) {
        MyRun my = new MyRun();
        Thread t = new Thread(my);
        t.start();

        for (int i = 0; i < 100; i++)
            System.out.println("main-----"+i);

        //匿名内部类
        new  Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("run");
            }
        }).start();
    }
}

/*
* 创建线程方式2:
*     实现接口Runnable
*    步骤:
*     1.定义类 实现Runnable接口
*     2.重写run方法
*     3.创建实现类对象
*     4.创建线程对象,并将实现类对象作为参数传递给线程对象的构造方法
*     5.调用start方法,启动线程
*    原理:
*       跟踪原码:
*         创建thread对象,将Runnable实现类对象传递给构造方法,将该对象赋值给Thread类中的target属性。
 *        start--->start0(本地方法,回调run方法)--->run(),thread类中的,方法中target.run(), target = new MyRun,
 *        接口类型引用指向自己的实现类对象,即多态,调用run方法,编译看父类,运行看子类。
*
*    好处:耦合度降低, 还可以继承其他类。
*
*    总结: 实际开发中建议使用的方式。
* */

class  MyRun  implements  Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++){
            System.out.println("run------------------------"+i);
        }
    }
}
2.3多线程第三种实现:实现Callable接口
  1. 相关方法介绍:
    1)V call(): 计算结果,如果无法计算结果,则抛出一个异常
    2)FutureTask(Callable callable): 创建一个 FutureTask,一旦运行就执行给定的 Callable
    3)V get(): 如有必要,等待计算完成,然后获取其结果

  2. 实现步骤:
    1)定义一个类MyCallable实现Callable接口
    2)在MyCallable类中重写call()方法
    3)创建MyCallable类的对象
    4)创建Future的实现类FutureTask对象,把MyCallable对象作为构造方法的参数
    5)创建Thread类的对象,把FutureTask对象作为构造方法的参数
    6)使用Thread类的对象调用start方法启动线程
    7)FutureTask对象用get方法,就可以获取线程结束之后的结果。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Demo6 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCall  my = new MyCall();
        FutureTask<String>  task = new FutureTask<>(my);
        Thread  t = new Thread(task);
        t.start();

        //获取线程任务结束后的结果
        //System.out.println(task.get());

        for (int i = 0; i < 100; i++){
            System.out.println("main----------"+i);
        }

        //匿名内部类
        new  Thread(new FutureTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("call");
                return "";
            }
        })).start();
    }
}
/*
* 创建线程方式3:
*    实现接口Callable
*      步骤:
*        1.定义类实现Callable<V>接口
*        2.重写call方法,方法的返回值是泛型上的类型
*        3.创建FutureTask对象,并传递实现类对象
*        4.创建线程对象,并传递FutureTask对象
*        5.调用start方法,启动线程
*        6.可以通过FutureTask对象中的get()方法获取子线程运行后的结果。
*     原理:
 *       跟踪原码:
 *         创建thread对象,将Runnable实现类对象FutureTask传递给构造方法,将该对象赋值给Thread类中的target属性。
 *         创建FutureTask对象时,将Callable实现类对象作为参数传递其构造方法,将该对象赋值给FutureTask中的callable属性
 *         start--->start0(本地方法,回调run方法)--->run(),thread类中的,方法中target.run(), target = new FutureTask,
 *        接口类型引用指向自己的实现类对象,即多态,调用run方法,编译看父类,运行看子类,执行是的FutureTask中的run方法,该
 *        run方法中,有callable.call(),callable = new  MyCall,多态,调用的是自己写的call方法。
 *
 *    好处:耦合度降低, 还可以继承其他类,获取线程任务结果后的结果。
 *
 *    总结: 实际开发中建议使用的方式。
* */

class  MyCall implements Callable<String>{

    @Override
    public String call() {
        for (int i = 0; i < 100; i++){
            System.out.println("子线程-----"+i);
        }
        return "执行了";
    }
}

/*
* 异常:
*   方法重写:
*      1.父类方法有throws,子类重写可以有throws,异常类型与父类一致或是父类异常的子集,或是没有throws
*      2.父类方法没有throws,子类重写可以没有throws,如果有throws,必须是运行时异常
* */

(三) Thread线程常用方法

3.1线程API之线程名称

  1. Thread(Runnable r , String name): 传递一个Runnable的任务对象,还可以传递一个name的线程名称
  2. void setName(String name): 将此线程的名称更改为等于参数name
  3. String getName(): 返回此线程的名称
  4. static Thread currentThread(): 返回对当前正在执行的线程对象的引用,哪个线程执行这行代码,就返回哪个线程

3.2线程API之线程休眠

static void sleep(long millis): 使当前正在执行的线程停留(暂停执行)指定的毫秒数

说明: 参数是毫秒值, 1000毫秒 = 1秒, 当线程执行到了sleep方法,休眠指定的毫秒数, 在休眠时间段内, 不再竞争CPU资源, 当休眠时间结束, 可以继续进行CPU资源竞争

3.3线程API之线程礼让

static void yield()
线程让步,暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程,若队列中没有同优先级的线程,忽略此方法

public class Demo7 {
    public static void main(String[] args) {
        MyRun1 my = new MyRun1();
        Thread t = new Thread(my,"线程1");
//        Thread t1 = new Thread(my,"线程2");
        t.start();
//        t1.start();

//        t.setName("我是线程1");

//        System.out.println(Thread.currentThread().getName());

        Thread.yield(); //礼让方法,暂停当前执行的线程,礼让其他线程去执行,但是不一定成功
        for (int i = 0; i < 10; i++){
            System.out.println(Thread.currentThread().getName()+"-------"+i);
        }
    }
}

class MyRun1  implements  Runnable{

    @Override
    public void run()  {

        for (int i = 0; i < 10; i++){
            /*try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }*/
            System.out.println(Thread.currentThread().getName()+"----"+i);
        }
    }
}
/*
* static  Thread  currentThread(): 获取线程对象,在哪调用获取的就是哪个线程的对象
* String  getName():获取线程名称, 默认名 : 主线程 :main   子线程:Thread-编号,编号从0开始
* 修改线程默认名字:
*    1.构造方法   new Thread(name)  new Thread(Runnable , name)
*    2.setName()
*
* 休眠方法:
*   static  void  sleep(毫秒) : 让线程睡眠一段时间
*                                意味着主动放弃执行资格,时间到,再次拥有执行资格,等待cpu调度。
* */

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值