Java学习第六周

1.多线程的创建方式2

  • 1)自定义一个类实现Runnable接口,

  • 2)实现接口里面的run方法--->完成耗时操作

  • 3)在main用户线程中创建当前这个类的实例--->"资源类对象"

  • 4)创建线程类Thread对象,然后将3)资源类对象 作为参数传递,启动线程!

2.Java设计模式 结构型设计-->代理模式-->静态代理

代理设计模式

代理核心思想

真实角色专注自己的事情(开发中,针对自己的业务) 代理角色帮助真实完成一件事情

静态代理

代理角色和真实角色:要实现同一个接口 动态代理 jdk动态代理 cglib动态代理(需要导入cglib.jar包)

第二种方式实现:

class MyRunnable implements Runnable{} MyRunnable my = new MyRunnable();----> 真实角色 Thread t1 = new Thread(my, "t1") ; ----> Thread代理角色

3.锁

synchronized(锁对象){
           //多条语句对共享数据操作      
           }

锁对象:可以是任意Java类对象,但是多个线程必须使用的同一个锁对象, 否则”锁不住"!

4.解决线程安全

校验多线程安全问题的标准( 使用标准来看多线程环境是否存在问题,以及解决方案)

1)是否是多线程环境---->是 2)是否有共享数据--- > 是 存在的 3)是否有多条语句对共享数据操作 tickets票:多条语句同时操作 将3)多条语句多共享数据的操作使用同步代码块包起来---解决线程安全问题 synchronized(锁对象){ 多条语句对共享数据操作 }

锁对象:

可以是任意Java类对象,但是多个线程必须使用的同一个锁对象, 否则”锁不住"!

什么是同步方法(非静态)?

如果一个方法中第一句话是一个同步代码块,可以将synchronized关键字定义在声明上 权限修饰符1 synchronized 返回值类型方法名(参数列表){ } 锁对象:this---代表类对象的地址值引用 如果是静态的同步方法,锁对象---->当前类名.class(字节码文件对象)

静态的同步方法的锁跟类相关---->当期类的字节码文件对象 类名.class

使用synchronized解决线程安全问题,

安全问题解决了,效率低,可能死锁现象

死锁:

两个线程出现了一种 互相等待的情况, A线程等待B线程释放锁, B线程等待A线程释放锁,造成死锁现象!

解决死锁问题

线程之间的通信必须使用的同一个资源!

5.为什么wait() notify(),线程等待,线程唤醒为什么定义Object类中?

这些方法都是 和锁对象有关系,而锁对象可以是任意Java类对象,而定义object类中 调用wait(),会立即释放锁!

6.throw和throws的区别

throw和throws共同点都是抛出的异常 throws: 1)抛出是在方法声明上抛出 public static Data string2Date(String source,String pattern)throws ParseException { return new SimplateDateFormat (pattern).parse (source); //String datestr ="2022-11-22" //使用s implateDateFormat里面传递的模式"yyy年MM月dd日",跟上面的格式不一致

} 2)throws的后面跟的异常类名,可以跟多个异常类名,中间逗号隔开 3)针对throws抛出的方法处理,谁调用这个方法,谁必须处理! (处理方式---交给调用者,继续throws或者try.. catch... finally) 4)throws它表示抛出异常的可能性

throw: 1)抛出是在方法体语句中 2)后面跟是异常对象名 throw new XXXEception (),只能某个异常对象名

  1. throw抛出的处理---交个方法中逻辑语句处理if语句 4)它表示抛出异常的肯定性,执行某段代码-定会有这个异常!

7.jdk5以后Lock锁(接口)--->ReetrantLock可重入的互斥锁

Lock实现提供比使用synchronized方法和语句可以获得的更广泛的锁定操作 实现类: 可重入的互斥锁 java.util.concurrent.locks.ReentrantLock

获取锁:指定的某个时刻 public void lock()

释放锁 : public void unlock()

finally代码:释放资源去使用的,一-定会执行, 除非一种特例(在执行finally之前, jvm退出了)

8.线程池

会创建一些固定的可重复使用的线程数,会在线程池中,循环利用 当某些线程使用完毕,不会被释放掉,而是归还连接池中,等待下一次再去利用! 成本比普通创建线程方式要大!

  • java.util.concurrent.Exceutors工厂类

  • public static ExecutorService newFixedThreadPool(int nThreads)创建固定的可重复的线程数的线程池

  • java.util.concurrent ExecutorService ----->接口的具体实现类public class ThreadPoolExecutor

  • <T> Future<T> submit(Callable<T> task):提交异步任务, 返回值就是异步任务计算的结果;

上面这个的返回值Future : 异步计算的结果---如果现在只是看多个线程是否能够并发的去强转CPU执行权,并没有返回结果,这个返回值可以不用返回! Callable:接口---->异步任务的执行类似于 之前Runnable接口

void shutdown(): 关闭线程池

<T> Future<T> submit(Callable<T> task):提交异步任务,返回值就是异步任务计算的结果; 上面这个的返回值Future :异步计算的结果---如果现在只是看多个线程是否能够并发的去强转CPU执行权,并没有返回结果 这个返回值可以不用返回!

线程池优化------>参数调优(7大参数)

线程池可以重复利用初始化的线程数量 最大线程数量 核心线程数量 最小线程数量 线程执行期间---->计量单位 超过最大线程数量---->启用拒绝策略 ThreadFactory:线程工厂,创建线程池

方法

private volatile int corePoolSize;核心线程数量 private volatile int maximumPoolSize;最大核心线程数 private volatile long keepAliveTime;线程在执行期间的存活时间 TimeUnit unit-->是一个枚举-->时间的计量单位 private final BlockingQueue<Runnable> workQueue,阻塞队列 private volatile ThreadFactory threadFactory;接口; 创建线程的线程工厂--> DefaultThreadFactory实现类是Executors的静态内部类,创建线程的

corePoolSize maximumPoolSize workQueue keepAliveTime threadFactory handLer

private volatile RejectedExecutionHandler handler 拒绝策略当的线程数量已经达到最大核心 线程数.通过上面ThreadFactory创建的线 程不能进入到线程池中;

Java提供了Timer:定时器---执行定时任务TimerTask

java. util. Timer:定时器(可以执行一次或者重复执行某个任务)

构造方法:

Timer():创建一个计时器

成员方法

public void cancel() 取消定时器 void schedule(TimerTask task,Date time) :在给定的日期时间来执行TimerTask定时任务 String dataStr = "2022-11-22 18:00" ;//---->日期文本---->java. util.Date(应用场景:引入使用io流的方式,在指定时间点上,递归删除带内容的目录里面所有的.java文件)

void schedule(TimerTask task,Long delay):在给定多少毫秒后(延迟时间)执行这个定时任务 public void schedule(TimerTask task, Long delay, Long period):在指定延迟时间(delay)执行任务,然后每经过固定延迟时间(period)重夏执行任务

t.cancel();取消定时器

schedule这些方法第一个参数都是定时任务: TimerTask是一个抽象类

1)可以定义具体的于类继承自TimerTask 2)直接可以使用抽象类的匿名内部类

9.IO流

使用java.io.File来描述路径形式

描述"D:\EE_ .2211 \day23 \code \Employee. java" File(File parent, String child) File(String pathname)推荐 File(String parent, String child)

基本功能:

创建文件`

public boolean createNewFile()throws IOException: 创建文件,如果不存在,创建,返回true public boolean mkdir(): 创建文件夹,如果存在了,则返回false;否则true public boolean mkdirs(): 创建多级目录,当父目录不存在的时候创建

判断

public boolean isFile(): 是否 是文件 public boolean isDirectory():是否是文件夹 public boolean isAbsolute():是否为绝对路径 public boolean exists():判断文件或者目录是否存在

删除

public boolean delete(): 删除由此抽象路径名表示的文件或目录(删除目录,目录必须为空)

java.io.File ----高级功能:获取指定目录下的所有的文件夹以及文件的Fiie数组

java. io.File:高级功能

  • public File[] listFiles(FileFilter filter) 获取File 数组的时候,就可以直接获取到指定条件的文件名称或者文件夹

  • 参数是一个接口: 文件过滤器

  • boolean accept(File pathname):

  • 抽象路径名称所表示的路径是否放在File列表中,取决于返回值true, 否则false,不放在列表中

  • public File[] listFiles(FilenameFilter filter):获取File数组的时候,就可以通过文件名称过滤器按照条件进行过滤

  • FilenameFilter接口

  • boolean accept(File dir, String name) :

参数1:指定的目录 参数2:文件名称 返回值: true, 将指定指定I月录下的文件放在File列表中,否则false

例题:获取D盘下所有的以.jpg结尾文件--->输出文件名称

public class FileTest2 {
    public static void main(String[] args) {
​
        //1)描述磁盘上抽象路径的表示d://
        File file = new File("D://") ;
        //public File[] listFiles(FileFilter filter) 获取File数组的时候,就可以直接获取到指定条件的文件名称或者文件夹
       /* File[] files = file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                //抽象路径名称所表示的路径是否放在File列表中,取决于返回值 true,将这个路径放在列表中,
                // 否则false,不放在列表中
                //获取D盘下所有的以.jpg结尾文件--->输出文件名称
​
               // System.out.println(pathname);
                return (pathname.isFile() && pathname.getName().endsWith(".jpg"));
            }
        });*/
        //public File[] listFiles(FilenameFilter filter):获取File数组的时候,就可以通过文件名称过滤器按照条件进行过滤
        File[] files = file.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                //创建File对象-->判断File是否为文件
                File f = new File(dir,name) ;//文件放在指定目录中
                //判断f的路径---->指定的文件 并且name文件名称必须以.jpg结尾
                boolean flag1 = f.isFile();
                boolean flag2 = (name.endsWith(".jpg")) ;
                return flag1 && flag2 ;
            }
        });
​
​
        //遍历File数组
        if(files!=null){
            for(File f:files){
                System.out.println(f.getName());
            }
        }
​
    }
}

10.递归算法

方法调用方法本身的一种现象! (并非是方法嵌套方法)

递明的使用:

1)需要定义一简陆 2)有规律 3)必须有出条件----> "死递归"

伪代码 public void show(int n){//5 while(n<0){ break; } System. out. printIn(n) ;//5 show(n--); }

方法递归: 1)需要有方法 2)有一定规律 3)有方法结束的条件(出口条件),否则"死递归"

构造方法没有递归

io流的分类

1)按流的方向划分 输入流---->读 输出流---->写 2)按流的类型划分--同时按方向划分: 字节流: 字节输入流: InputStream--->不能实例化--->具体的子类:针对文件的字节输入流FileInputStream 字节输出流: 0utputStream--->不能实例化--->具体的子类:针对文件的字节输出流FileOutputStrean public File0utputStream(String name, boolean append) throws FileNotFoundException

创建字节文件输出流对象,实现文件的末尾追加,而不将之前覆盖,第二个参数必须为true

字节缓冲流(字节高效流) 字节缓冲输入流:BufferedInputStream 字节缓冲输出流:BufferedOutputStream

字符流: 字符输入流 字符输出流

例题:在当前项目输出一个文本文本,里面同时写入内容

public class IODemo {
    public static void main(String[] args) throws IOException {
        //创建字节输出流对象
        //OutputStream抽象类,不能new
        //public FileOutputStream(File file)
        //public FileOutputStream(String pathname):推荐 直接跟路径名称
        FileOutputStream fos = new FileOutputStream("fos.txt") ;
​
        //写数据
        //public void write(int b)  :写一个字节
        fos.write(97) ;
        fos.write("\r\n".getBytes());
        fos.write(98) ;
      /*  fos.write(99) ;
        fos.write(100) ;
        //public void write(byte[] bytes):写一个字节数组
        byte[] bytes = {65,66,67,68,69,70} ;
        fos.write(bytes);*/
        //释放资源
        fos.close();
    }
}
  1. public FileOutputStream(String name,boolean append) throws FileNotFoundException创建字节文件输出流对象,实现文件的末尾追加,而不将之前覆盖,第二个参数必须为true

  2. IO流操作的时候,加入异常处理代码格式---->开发中 try...catch...finally 使用捕获一次

11.字节输入流

InputStream--->读 抽象类

提供子类:FileInputStream:针对文件操作的字节输入流

  • 1)创建文件字节输入流对象

    • FileInputStream fis = new FileInputStream("fis.txt") ;

  • 2)读文件

    • public int read() throws IOException:一次读取一个字节,返回字节数

    • public int read(byte[] b) throws IOException:一次读取一个字节数组

  • 3)释放资源

注意乱码

文件字节输入流一次读取一个字节,将文件内容输出控制台上,中文出现乱码,因为

  • 字节流读取字节的时候---将字节--->强转成char,只考虑英文(abcdxxx)--->97---(char)97,当英文的后面有中文拼接

  • 无法解析强转了--->乱码---->java才提供了字符流

字节流和字符流的使用时间

什么时候使用字符流,当使用记事本打开能读懂的就使用字符;打开读不懂,用字节!(读图片文件/视频/音频)

例题:当前项目下的IODemo3.java复制到D:\EE_2211\day24\Copy.java

public class IOTest {
    public static void main(String[] args) throws IOException {
        //使用字节输入操作---->源文件FileInputStream(String pathname)
        FileInputStream fis = new FileInputStream("IODemo3.java") ;
        // 使用字节输出流操作---->目的地文件 FileOutputStream(String pathname)
        FileOutputStream fos = new FileOutputStream("D:\\EE_2211\\day24\\Copy.java") ;
​
        //一次读取一个字节
      /*  int len = 0 ;
        while((len=fis.read())!=-1){//不断的再去一次读取字节
            //不断写字节
            fos.write(len); //写入到流对象汇总
        }*/
​
        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = 0 ; //实际字节数
        while((len=fis.read(bytes))!=-1){
            //字节输出流写一个数组到目标文件中
            fos.write(bytes,0,len);
        }
​
        //释放资源
        fos.close();
        fis.close();
    }
}

System.currentTimeMillis() ;获取当前时间

12.字节缓冲输出流/输入流 (高效字节流)

BuffedOutputStream/BufferedInputStream:只是提供一个字节缓冲区,本身就是一个字节数组,不会直接操作文件

操作具体的文件使用都是基本字节流FileInputStream/FileOutputStream

  • public BufferedOutputStream(OutputStream out):创建一个字节缓冲输出流对象,默认缓冲区大小(足够大)

  • public BufferedInputStream(InputStream in):创建一个字节缓冲输入流对象,默认缓冲大小

读取方式:

一次读取一个字节

int by = 0 ;//实际字节数 while((by=bis.read())!=-1){ System.out.print((char)by); }

一次读取一个字节数组

byte[] bytes = new byte[1024] ; int len = 0 ; while((len=bis.read(bytes))!=-1){ System.out.println(new String(bytes,0,len)); }

13.字符流

Writer:具体的子类

  • public OutputStreamWriter(OutputStream out):字符转换输出流(可以将基本字节输出流转换成字符输出流),平台默认的字符集编码(idea,utf-8)

  • public OutputStreamWriter(OutputStream out,String charsetName):字符转换输出流 ,指定一个编码字符集

    写的功能

  • void write(char[] cbuf)写入一个字符数组。

  • abstract void write(char[] cbuf, int off, int len) 写入字符数组的一部分。

  • void write(int c) 写一个字符

  • void write(String str)写一个字符串

  • void write(String str, int off, int len) :写入字符串的一部分

    Reader:抽象类

    具体子类

  • public InputStreamReader(InputStream in):创建字符转换输入流,以平台默认字符集解码

  • public InputStreamReader(InputStream in,String charsetName):创建字符转换输入流对象,指定字符集解码

    read的功能

  • public int read(char[] cbuf):读取字符数组

  • public int read():读一个字符

  • InputStreamReader/OutputStreamWriter:字符转换流弊端:代码格式复杂,不能直接操作文件!

字符流转换

public InputStreamReader(InputStream in)

public OutputStreamWriter(OutputStream out)

上面字符转换流使用的时候,无法直接直接操作具体文件,里面包装一层字节流操作,书写格式繁琐!

提供了他们具体的子类 ---字符转换流的便捷类,跟idea平台默认字符集一致

  • FileReader(File/String pathname)

  • FileWriter(File/String pathname)

  • FileWriter(File/String pathname,boolean append):第二个参数为true,追加内容

  • 字符流针对文件(使用高级记事本打开能读懂的),使用字符流操作

InputStreamReader isr = new InputStreamReader( new FileInputStream("osw.txt"),"gbk") ;//解码gbk InputStreamReader isr = new InputStreamReader( new FileInputStream("osw.txt"),"utf-8") ;解码utf-8 public InputStreamReader(InputStream in):创建字符转换输入流,以平台默认字符集解码

BufferedReader(Reader in):字符缓冲输入流

InputStream in = System.in ; //标准输入流---等待录入 创建字符输入流:Reader抽象类 InputStreamReader是具体的子类 构造方法InputStreamReader(InputStream in ) Reader reader = new InputStreamReader(in) ;

创建一个字符缓冲输入流对象BufferedReader br = new BufferedReader(reader) ;

一步走

BufferedReader br = new BufferedReader( new InputStreamReader(System.in)) ;

利用BufferedReader一次读取一行String line = br.readLine() ;

14.BufferedReader:字符缓冲输入BufferedWriter:字符缓冲输出流

他们不能直接操作文件,提供缓冲区让读写效率更高,特有方式 BufferedReader一次读取一行/可以作为键盘录入(录入一行字符串内容)

字符流针对文本文件(记事本打开能看懂的)-->字符流读写复制

1)字符转换流InputStreamReader/OutputStreamWriter 一次读取一个字符/一次读取一个字符数组 2)使用字符转换流的便捷类FileReader/FileWriter 可以直击操作文件 一次读取一个字符/一次读取一个字符数组 3)使用字符缓冲流BufferedReader/BufferedWriter: 一次读取一个字符/一次读取一个字符数组 4)使用字符缓冲流BufferedReader/BufferedWriter :一次读取一行特有方式(推荐!) 读写复制

15.序列化

将一个Java对象(当前的类以及属性--->签名信息)--->"流数据" 前提条件就是 当前对象的所在类型必须实现

  • java.io.serializable序列化接口---->实现了这个接口的类才能被序列化,产生固定serialVersionUID唯一的标识ID

  • 序列化:ObjectOutputStream---->将java对象--->写到序列化流中

  • public ObjectOutputStream(OutputStream out)

  • 反序列化:ObjectInputStream---->将序列化中流数据的信息---->还原成Java对象

类的信息一旦更改,里面的类的签名信息(唯一标识 序列化UID就发生变化 )

  • Personc.class------>已经序列化----UId=100

  • 现在反序列化的,将Person.class---->改动了----->UId=200

将Person对象变成流数据,进行数据传输,必须实现serializable接口:里面什么都没有 ---"标记接口"

16.java.util.Properties(很重要):属性列表集合类

Properties类表示一组持久的属性。

  • Properties可以保存到流中或从流中加载。(重要的地方)

  • 属性列表中的每个键及其对应的值都是一个字符串。

  • 继承Hashtable---->实现Map接口---->存储数据,取出数据----都可以使用Map的方式

  • 构造方法:public Properties():创建空的属性列表

添加/遍历---可以使用Map集合的方式

1)但是,使用特有功能---->最大特点:键和值必须是string,后期经常用在xxx. properties属性列表文件 key1=value1 key2=value2 2)一些功能和流有很大关系 将属性列表文件的内容加载到属性列表中Properties---->load (Reader in) 将属性列表中的内容保存到指定文件中---->store (Writer out, string文件列表描述) 3)如何读取src'下面的xx . properties配置文件 配置文件在项目下xx. txt

常用的Map遍历方式

获取所有的键的集合 Set<K> keySet() Set<Object> keySet = prop.keySet();

java. util. Properites属性列表有自己的遍历方式---底层基于Map实现的

添加元素:

pubLic Object setProperty( String key,String valve ) 遍历属性列表 public Set<String> stringPropertyNames() 获取属性列表中的所有的键 public String getProperty(String key) 使用此属性列表中指定的键搜索属性

Properties特有方式

public void load(Reader reader)throws IOException : 将指定文件中的内容加载属性集合列表中(内容键值对 key=value) void store(Writer writer, String comments) :将属性列表中的内容保存指定文件中(以"键=值"元素对进行保存) 第一个参数:字符输出/使用字节输出流 第二个参数:属性列表的描述

如何读src下面的xx.properties

1)获取当前类的字节码文件对象 --->Class 正在运行的java类对象 Class clazz = Test3.class ; System.out.println(clazz);

2)Class类---获取类加载器---解析这个里面所有成员(变量/方法..校验) public ClassLoader getClassLoader() ClassLoader classLoader = clazz.getClassLoader();

3)ClassLoader---->public InputStream getResourceAsStream(String name):参数名称:就是src下面配置文件名称 获取资源文件所在输入流对象--->将资源文件的内容读取到了字节输入流中 InputStream inputStream = classLoader.getResourceAsStream("name.properties");

4)将输入流对象的内容加载属性列表中

一步走

前提:配置文件必须在src下面 InputStream inputStream = Test3.class.getClassLoader(). getResourceAsStream("name.properties");

17.网络编程

网络三要素

找到高圆圆 1)网络中需要知道ip地址 2)找到她的ip,对她说话--->对着"耳朵"-----> 端口port 3)对她说话"i Love you"---> 她听不懂, 说"我爱你"---->需要有一个规则----"协议"

ip使用点分十进制法,中间使用.隔开

A类 国家大部门---->前一个号段是网络号段,后面三个主机号段 B类校园/大公司服务器机房/:前面两个网络号段,后面使用两个注解号段 C类私人地址: 前面三个为网络号段,后面是主机号段 192.168.251.1---> port端口 port端口360软件都可以查看你电脑所有客户端软件的端口号: 范围: 0~65535里面0~1024属于保留端口

传输协议

UDP协议-->数据报包(数据包的报文) 1)不需要建立连接通道 2)不可靠协议,不安全的 3)发送数据大小有限制 TCP协议-->最基本的

UDP发送端和接收端的实现(了解)-->不可靠连接

java. net. InetAddress:代表互联网ip地址对象 想获取计算机的主机名称或者获取计算机的ip地址字符串形式? public static InetAddress getByName(String tost) throws UnknownHostException 通过计算机主机名称或者是字符串形式的ip地址--->获取互联网ip地址对象

Socket编程( ”流的套接字")

不管是UDP协议发送数据还是TCP方式发送数据 1)两端都必须有socket对象(Upd发送端 和接收端/ TCP客户端 和服务器端) 2)upd发送端或者TCP客户端都需要有ip地址以及端口 3)socket底层其实一种”物理层”---比特流的方式进行数据发送和接收

UDP接收端的代码实现

  • 1)创建接收端的Socket对象,绑定端口

  • 2)创建一个接收容器--->数据包--->自定义字节缓冲区,将发送的数据包

  • 3)接收

  • 4)从接收容器中解析数据包的实际内容数据

  • 5)展示数据

Upd方式--->不需要建立连接通道,不可靠连接

Udp发送端的步骤 1)创建发送端的socket,DatagramSocket ds = new DatagramSocket() ;

2)创建数据报包DatagramPacket

  • public DatagramPacket(byte[] buf, 要发送数据---转换成字节数组

    int length, 实际字节数长度

    InetAddress address, ip地址对象

    int port) 端口号

3)使用发送端的Socket将数据存储数据包中,发送(本质存储数据包)send() 4)释放资源close()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值