20221121-20221125JAVA周总结

多线程创建方式

第二种方式—实现Runnab接口

  • 1)自定义一个类实现Runnable接口,
  • 2)实现接口里面的run方法—>完成耗时操作
  • 3)在main用户线程中创建当前这个类的实例—>“资源类对象”
  • 4)创建线程类Thread对象,然后将3)资源类对象 作为参数传递,启动线程!

同步方法

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

如果一个方法中第一句话是一个同步代码块,可以将synchronized关键字定义在声明上
权限修饰符 synchronized 返回值类型 方法名(参数列表){

}
龟兔赛跑例子

/* 赛道---->资源类对象
 */
public class Race  implements Runnable{
    //声明String 胜利者
    private static String winner ;
    @Override
    public void run() {
        //距离---定义0-199步
        for(int x = 0 ; x <200 ; x++){//x就是步数
                //如果线程名称是兔子,需要让它睡眠
                if(Thread.currentThread().getName().equals("兔子") && (x%10==0)){
                    //睡眠给5毫秒
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            System.out.println(Thread.currentThread().getName()+"跑了---->"+x+"步");

            //调用一个方法,比赛是否结束
            boolean flag = gameOver(x) ;//传入的步数
            if(flag){
                break;
            }

        }
    }
    //定了这个方法,必须是否结束
    public boolean gameOver(int x) {//步数
        if(winner!=null){
            //已经有胜利者了结束
            return  true ;
        }{//局部代码块
            //判断x的步数
            if(x>=199){
                //给winner赋值
                winner = Thread.currentThread().getName() ;
                //打印胜利者
                System.out.println("winer is--->"+winner);
               return true ;
            }
        }
        return false ;
    }


    //用户线程
    public static void main(String[] args) {

        //创建一个赛道
        Race race = new Race() ;
        //创建两个线程
        //兔子和乌龟共用一个赛道
        Thread t1 = new Thread(race,"兔子") ;
        Thread t2 = new Thread(race,"乌龟") ;

        //启动线程
        t1.start() ;
        t2.start() ;
    }
}

死锁问题

两个线程出现了一种互相等待的情况,A线程等待B线程释放锁,B线程等待A线程释放锁,造成死锁现象!
解决死锁问题—>线程之间的通信必须使用的同一个资源! (生产者和消费者模式思想)

代理设计模式

  • 代理核心思想:
    真实角色专注自己的事情(开发中,针对自己的业务)
    代理角色帮助真实完成一件事情
  • 静态代理
    代理角色和真实角色要实现同一个接口
  • 动态代理:
    jdk动态代理
    cglib动态代理(需要导入cglib.jar包)

生产者消费者思想

生产者消费者思想

Lock接口

Lock这个接口

  • Lock实现提供比使用synchronized方法和语句可以获得的更广泛的锁定操作
  • 实现类:
    可重入的互斥锁 java.util.concurrent.locks.ReentrantLock
    获取锁:指定的某个时刻 public void lock()
    释放锁 : public void unlock()
    Lock l = …;
    l.lock();
    try {
    // access the resource protected by this lock
    } finally {
    l.unlock(); //释放锁(系统相关的资源)
    }
    注意:finally代码一定实现

线程池

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

  • 成本比普通创建线程方式要大!
  • java.util.concurrent.Exceutors 工厂类
  • public static ExecutorService newFixedThreadPool(int nThreads)
  • 创建固定的可重复的线程数的线程池
  • java.util.concurrent ExecutorService ----->接口的具体实现类 public class ThreadPoolExecutor
  • Future submit(Callable task):提交异步任务,返回值就是异步任务计算的结果;
  • 上面这个的返回值Future :异步计算的结果—如果现在只是看多个线程是否能够并发的去强转CPU执行权,并没有返回结果
  • 这个返回值可以不用返回!
  • Callable:接口---->异步任务的执行 类似于 之前Runnable接口
  • void shutdown():关闭线程池

Timer计时器

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)重复执行任务
    schedule这些方法第一个参数都是定时任务:TimerTask是一个抽象类,
  • 1)可以定义具体的子类继承自TimerTask
  • 2)直接可以使用抽象类的匿名内部类

JAVA中的文件及文件夹等操作

  • 基本功能:
    创建文件/文件夹
    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():删除由此抽象路径名表示的文件或目录 (删除目录,目录必须为空)

io流中File的高级功能

  • public File[] listFiles():获取指定抽象路径表示下的所有的File数组 推荐---->使用File的功能进行判断
  • public String[] list():抽象路径名表示的目录中的文件和目录。
 /* 需求:
 *      获取D盘下所有的以.jpg结尾文件--->输出文件名称
 */
public class FileTest {
    public static void main(String[] args) {

        //1)描述磁盘上抽象路径的表示d://
        File file = new File("D://") ;
        //public String[] list():抽象路径名表示的目录中的文件和目录。
       /* String[] strs = file.list();
        for(String s:strs){
            System.out.println(s) ;
        }*/
        //public File[] listFiles():获取指定抽象路径表示下的所有的File数组  推荐---->使用File的功能进行判断
        File[] files = file.listFiles();
        //遍历之前:非空判断,防止空指针异常
        if(files!=null){
            for(File f :files){
                //f---->有文件/文件夹
                //判断是文件
                if(f.isFile()){
                    //以.jpg结尾
                    if(f.getName().endsWith(".jpg")){      System.out.println(f.getName());//String getName():获取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,将指定指定目录下的文件放在File列表中;否则false

递归思想

递归:

  • 方法调用本身的一种现象! 不是方法嵌套方法
    java.lang.Math.max(10,Math.max(20,15)) ;
  • 伪代码
    public void show(int n){//5
    while(n<0){
    break ;
    }
    System.out.println(n) ;//5
    show(n–);
    }
  • 方法递归:
    1)需要有方法
    2)有一定规律
    3)有方法结束的条件(出口条件),否则 “死递归”
    构造方法没有递归

实例:不死神兔

/**
 * 有一个很有名的数学逻辑题叫做不死神兔问题。
 *      有一对兔子,
 * 		从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,
 * 		问第二十个月的兔子对数为多少?
 * 规律:
 *    兔子的对数
 *    第一个月:1
 *    第二个月:1
 *    第三个月:2
 *    第四个月:3
 *    第五个月:5
 *    第六个月:8
 *    底七个月:13
 *    ....
 *   第一个月和第二个月兔子的对数是1
 *  从第三个月开始,每一月兔子对数是前两个月兔子对数之和!
 *
 *
 *  使用a,b代表相邻两个月兔子的对数
 *   第一个,第二个月 a=1,b=1
 *   第二月,第三个月 a=1,b=2
 *   第三个月,第四个月 a=2,b=3
 *   第四个月,第五个月 a=3,b=5
 *
 */
public class Test1 {
    public static void main(String[] args) {
        //数组的方式去实现
        //创建一个数组:动态初始化
        int[] arr = new int[20] ; //第二十个月
        //第一个月和第二个都是1
        arr[0] = 1 ;
        arr[1] = 1 ;
        //从第三个月开始,每一月兔子对数是前两个月兔子对数之和!
        for(int x = 2 ;x<arr.length;x++){
            arr[x] = arr[x-1] + arr[x-2] ;
        }
        //输出最后一个元素
        System.out.println("第二十个月兔子对数:"+arr[19]); //6765
        System.out.println("-----------------------------------------------------") ;

        //递归:定义一个方法

        //long time = System.currentTimeMillis() ;
        System.out.println("第二十个月的兔子的对数是:"+getRabbit(20));
       // long end = System.currentTimeMillis();
       // System.out.println("耗时"+(end-time)+"毫秒");


    }
    //定义一个方法
    public static int getRabbit(int n){//代表的第几个月
        //第一个月和第二个月兔子的对数是1---->方法递归的出口条件
        if(n==1 || n==2){
            return  1;
        }else {
            //从第三个月开始,每一个月兔子对数是前两个月兔子对数之和!
            return getRabbit(n-1)+getRabbit(n-2) ;
        }
    }

}

Io流

Io流的分类

  • 1)按流的方向划分
    输入流 ---->读
    输出流 ---->写
  • 2)按流的类型划分–同时按方向划分:
    字节流
    字节输入流:InputStream—>不能实例化—>具体的子类:针对文件的字节输入流 FileInputStream
    字节输出流:OutputStream—>不能实例化—>具体的子类:针对文件的字节输出流 FileOutputStream
    字节缓冲流(字节高效流)
    字节缓冲输入流:BufferedInputStream
    字节缓冲输出流:BufferedInputStream
    字符流
    字符输入流
    字符输出流
  • windows系统下通过io流的方式(字节流) 写换行—>“\r\n” 换行符号
  • Linux系统:“\r”

异常捕获

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

字节输出流

字节输入流:InputStream—>读 抽象类

  • 提供子类:FileInputStream:针对文件操作的字节输入流
  • 1)创建文件字节输入流对象
  • 2)读文件
    public int read() throws IOException:一次读取一个字节,返回字节数
    public int read(byte[] b) throws IOException:一次读取一个字节数组
  • 3)释放资源
    文件字节输入流一次读取一个字节,将文件内容输出控制台上,中文出现乱码,因为
    字节流读取字节的时候—将字节—>强转成char,只考虑英文(abcdxxx)—>97—(char)97,当英文的后面有中文拼接
    无法解析强转了—>乱码---->java才提供了字符流
    什么时候使用字符流,当使用记事本打开能读懂的就使用字符;打开读不懂,用字节!(读图片文件/视频/音频)
  • 使用基本字节流一次读取一个字节数组:
    public int read(byte[] b) throws IOException:一次读取一个字节数组
代码实现
//针对文件读写复制,一次读取一个字节
public static void copyFile(String srcFile,String destFile){
    //操作源文件
    FileInputStream fis = new FileInputStream(srcFile) ;
    //操作目的文件
    FileOutputStream fos = new FileOutputStream(destFile) ;
    
    //一次读取一个字节
    int by = 0 ;//读取的字节数
    while((by=fis.read())!=-1){
        //写字节
        fos.write(by) ;
    }
    
    //释放资源
    fos.close() ;
    fis.close() ;
}
  • 当需要显示传送时间时
    long start = System.currentTimeMillis() ;
    // copyFile(“参数1:源文件地址”,“新文件名”) ;
    long end = System.currentTimeMillis() ;
    System.out.println(“共耗时:”+(end-start)+“毫秒”) ;
    }
throw和throws的区别

1)抛出的位置不同
throws抛出在方法声明上
throw抛出在方法体中
2)后面使用异常格式不同
throws 后面跟的异常类名,而且中间逗号隔开,可以抛出多个异常
throw 后面跟的异常对象 new XXXException() ;跟的具体的某一个异常对象
3)处理异常方式不同
针对带有throws的方法,异常处理是交给调用者处理!
针对throw抛出异常的处理,交给方法体中逻辑语句处理! 举例
if(条件表达式){
thrwo new XXException();
}
4)是否抛出的异常的肯定性
throws:表示抛出异常的可能性,执行某段代码,可能出现问题
String的日期文本---->java.util.Date格式---->解析parse (通过SimpleDateFormat)
“2022-11-24”
throw:表示抛出异常的肯定性,执行方法体中某段代码,一定会出现异常!

字符流

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:字符转换流弊端:代码格式复杂,不能直接操作文件!

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

  • BuffedOutputStream/BufferedInputStream:只是提供一个字节缓冲区,本身就是一个字节数组,不会直接操作文件
    操作具体的文件使用都是基本字节流FileInputStream/FileOutputStream

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

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

  • BufferedReader:字符缓冲输入流

  • BufferedWriter:字符缓冲输出流

  • 他们不能直接操作文件,提供缓冲区让读写效率更高,特有方式

  • BufferedReader一次读取一行/可以作为键盘录入(录入一行字符串内容)

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

  • 1)字符转换流InputStreamReader/OutputStreamWriter 一次读取一个字符/一次读取一个字符数组

  • 2)使用字符转换流的便捷类FileReader/FileWriter 可以直击操作文件 一次读取一个字符/一次读取一个字符数组

  • 3)使用字符缓冲流BufferedReader/BufferedWriter: 一次读取一个字符/一次读取一个字符数组

  • 4)使用字符缓冲流BufferedReader/BufferedWriter :一次读取一行特有方式(推荐!)

举例实现序列化于反序列化
public class IODemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
//        write() ;
        read() ;
    }
    //反序列化操作:将流数据--->还原成Java对象
    private static void read() throws IOException, ClassNotFoundException {
        //public ObjectInputStream(InputStream in)throws IOException
        //创建反序列化流对象
        ObjectInputStream bis = new ObjectInputStream(
                new FileInputStream("oos.txt")) ;
        //将序列化的流数据--->还原成Java对象
       // public final Object readObject()throws IOException, ClassNotFoundException
        Person p = (Person)bis.readObject();
        System.out.println(p);
    }
    //序列化操作
    private static void write() throws IOException {
        //创建一个Java对象
        Person p = new Person("高圆圆",44) ;
        //public ObjectOutputStream(OutputStream out)
        //创建序列化流中
        ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("oos.txt")) ;
        //public final void writeObject(Object obj)
        oos.writeObject(p); //java.io.NotSerializableException:当前p对象所在的类型没有是实现序列化接口
        //释放资源
        oos.close();
    }
}

初步网络编程

Properties类

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

  • Properties可以保存到流中或从流中加载。(重要的地方)
  • 属性列表中的每个键及其对应的值都是一个字符串。
  • 继承Hashtable---->实现Map接口---->存储数据,取出数据----都可以使用Map的方式
  • 构造方法:
    public Properties():创建空的属性列表
遍历方式

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

  • 添加元素:
    public Object setProperty(String key, String value)
    遍历属性列表
    public Set stringPropertyNames()获取属性列表中的所有的键
    public String getProperty(String key)使用此属性列表中指定的键搜索属性
Properties特有方式
  • public void load(Reader reader)throws IOException :
  • 将指定文件中的内容加载属性集合列表中(内容键值对 key=value)
  • void store(Writer writer, String comments) :将属性列表中的内容保存指定文件中(以"键=值"元素对进行保存)
    第一个参数:字符输出/使用字节输出流
    第二个参数:属性列表的描述
  • 相当于:
    打游戏---->进度的加载
    关卡的保存
如何读取src(类路径下)xxx.properties配置文件

属性配置文件它里面有颜色标记的,放在src下面的

public class Test3 {
    public static void main(String[] args) throws IOException {
        //就需要将src下面的xxx.properties内容加载属性列表汇总

        //创建属性列表Properties
        Properties prop = new Properties() ;
        System.out.println(prop);

        //如何读src下面的xx.properties
        //1)获取当前类的字节码文件对象 --->Class 正在运行的java类对象
      //  Class clazz = Test3.class ;
        //System.out.println(clazz);//class com.qf.properties_01.Test3
        //2)Class类---获取类加载器---解析这个里面所有成员(变量/方法..校验)
        //public ClassLoader getClassLoader()
       // ClassLoader classLoader = clazz.getClassLoader();

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

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


        //4)将输入流对象的内容加载属性列表中
        prop.load(inputStream);
        //通过key获取value
        String value = prop.getProperty("甲");
        System.out.println(value);
        String value2 = prop.getProperty("乙");
        System.out.println(value2);
        //完成自己的业务操作

        System.out.println(prop);
    }
}

互联网ip地址

  • 如何获取计算机的主机名称或者获取计算机的ip地址字符串形式
    public static InetAddress getByName(String host)
    throws UnknownHostException
    通过计算机主机名称或者是字符串形式的ip地址—>获取互联网ip地址对象
public class InetAddressDemo {
    public static void main(String[] args) throws UnknownHostException {

        //public static InetAddress getByName(String host)throws UnknownHostException
        //1)可以通过计算机机器名称获取ip地址对象
        InetAddress inetAddress = InetAddress.getByName("主机名"); //还可以指定ip地址字符串
        System.out.println(inetAddress);//DESKTOP-Q62EUJH/192.168.5.5

        //互联网ip地址对象:  主机名称/ip地址字符串
        //public String getHostName() :通过ip地址对象获取计算机机器名
        String hostName = inetAddress.getHostName() ;
        System.out.println(hostName);
        //获取里面的包含ip地址字符串形式
//        public String getHostAddress()
        String ip = inetAddress.getHostAddress();
        System.out.println(ip);
    }
}

UDP

  • 发送代码实现
    Udp发送端的步骤
    1)创建发送端的socket
    2)创建数据报包
    3)使用发送端的Socket将数据存储数据包中, 发送(本质存储数据包)
    4)释放资源
public class UdpSend {
    public static void main(String[] args) throws IOException {
        //1)创建发送端的socket
        //此类表示用于发送和接收数据报数据包的套接字。 DatagramSocket
        //public DatagramSocket() throws SocketException
        DatagramSocket ds = new DatagramSocket() ;

        // 2)创建数据报包DatagramPacket
        /**
         * public DatagramPacket(byte[] buf,  要发送数据---转换成字节数组
         *                       int length,  实际字节数长度
         *                       InetAddress address,  ip地址对象
         *                       int port)  端口号
         */
        byte[] bytes = "hello,UDP我来了".getBytes() ;
        int length = bytes.length ;
        InetAddress inetAddress = InetAddress.getByName("192.168.1.5");//如果自己玩,没有网线,无线ip不断变的--->本地回环地址127.0.0.1
        int port = 10086 ;
        DatagramPacket dp = new DatagramPacket(bytes,length,inetAddress,port);

        //3)使用发送端的Socket将数据存储数据包中, 发送(本质存储数据包)
        //public void send(DatagramPacket p) throws IOException
        ds.send(dp) ;

        //4)释放资源
        ds.close() ;
    }
}

  • 接收代码实现
    1)创建接收端的Socket对象,绑定端口
    2)创建一个接收容器—>数据包—>自定义字节缓冲区,将发送的数据包
    3)接收
    4)从接收容器中解析数据包的实际内容数据
    5)展示数据
  • 先运行接收端,而且接收端不能运行多次,否则端口被占用!
public class UDPReceiver {
    public static void main(String[] args) throws IOException {
        //1)创建接收端的Socket对象,绑定端口
        //public DatagramSocket(int port)  throws SocketException
        DatagramSocket ds = new DatagramSocket(10086) ;

        //2)创建一个接收容器--->数据包--->自定义字节缓冲区,将发送的数据包
       // public DatagramPacket(byte[] buf, int length)构造一个DatagramPacket用于接收长度的数据包length 。
        byte[] bytes = new byte[1024] ;//1024或者1024整数倍
        int length = bytes.length ;
        DatagramPacket dp = new DatagramPacket(bytes,length) ; //将发送端数据缓冲到这个接收容器中

        //3)接收,以上面这个接收容器来接收
        //public void receive(DatagramPacket p)throws IOException
        ds.receive(dp);

        //4)从接收容器中解析数据包的实际内容数据
        //从接收容器中获取public byte[] getData() 实际缓冲区的对象(从上bytes分段取数据)
        byte[] bytes2 = dp.getData();
        //获取里面实际缓冲区的长度
       // public int getLength()
        int length2 = dp.getLength();
        //展示数据---分段取数据,每次从0开始取实际长度
        String msg = new String(bytes2,0,length2) ;
        //数据包里面获取哪一个ip地址发来的--->ip地址字符串形式
        //public InetAddress getAddress()--->InetAddress--->getHostAddress()--->String IP地址字符串
        String ip = dp.getAddress().getHostAddress() ;
        System.out.println("data from --->"+ip+",发送内容是:"+msg);

        //释放资源
        ds.close();


    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值