day08_多线程_网编

一. 枚举

1.1 枚举概述

是一种特殊的类,经常用于描述几个常用的有限的值

1.2 自定义枚举

格式:

​ public enum 枚举名{

​ 枚举项(描述一个固定的值),枚举项,...

​ 构造方法...

​ 成员方法...

​ 成员变量...

​ }

使用:

​ 枚举名.枚举项

java 复制代码
//描述季节的固定的几个值
public enum Season {
    //四个季节,四个枚举项来表示
    //spring, summer, autumn, winner
    //枚举项都是静态的并且被final修饰的变量,所以命名一般都是大写
    SPRING, SUMMER, AUTUMN, WINNER;
    //SPRING(1), SUMMER, AUTUMN, WINNER;

    //枚举的构造方法不能被外部直接使用new调用
    /*private Season(){

    }*/

    /*private Season(int num){

    }*/

    /*public void show(){

    }*/
}





public class Test {

    public static void main(String[] args) {
        System.out.println(Season.SPRING);
        System.out.println(Season.SUMMER);
        System.out.println(Season.AUTUMN);
        System.out.println(Season.WINNER);

        //所有的枚举都继承java.Enum类
        //Enum e = Season.SPRING;
        Season s = Season.SPRING;
        int result = s.compareTo(Season.SUMMER);
        System.out.println(result);

        String name = s.name();
        System.out.println(name);
        wuNong(Season.SPRING);

    }

    //闫晨宇提供一个务农的方法
    public static void wuNong(Season season){
        if (season.equals(Season.SPRING)){
            System.out.println("播种");
        }else if (season.equals(Season.SUMMER)) {
            System.out.println("除草");
        }else if (season.equals(Season.AUTUMN)) {
            System.out.println("收果");
        }else if (season.equals(Season.WINNER)) {
            System.out.println("收秸秆");
        }
    }

}

1.3 枚举的本质

枚举本质上就是一个类

所有的枚举都继承了java.lang.Enum

枚举项本质上就是当前枚举的一个变量,被static修饰

二.多线程

2.1 多线程概述

并行: 多个任务在同一个时间点同时执行

并发: 多个任务在同一个时间片段内,交替执行

进程: 计算机分配资源的基本单位

线程: 进程中的一个执行单元(执行路径)

前提: 单核单线程理解

2.2 多线程的三种创建方式

2.2.1 继承Thread类
java 复制代码
//Thread就是线程
public class MyThread extends Thread {

    //写任务的代码
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("MyThread.run中: 我爱柳岩" + i);
        }
    }
}



public class Test {

    public static void main(String[] args) {
        //1.创建MyThread类的对象
        MyThread mt = new MyThread();

        //2.调用start方法,开启线程

        mt.start();//用于开启线程,并且自动的执行线程任务run方法  子线程

        //jvm会自动开启一个线程,执行main方法中的代码, 该线程  main线程(主线程)
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程: 我爱舒淇"+i);
        }
    }
}

注意: 开启线程是调用Thread类的start方法,如果手动调用run方法,不叫开启线程,在当前线程中执行run方法的代码

2.2.2 实现Runnable接口
java 复制代码
/*
    Runnable接口是jdk提供的专门书写线程任务的接口
 */
//自定义的类用于书写线程任务
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("我爱柳岩的妹妹..."+i);
        }
    }
}
java 复制代码
public class Test {

    public static void main(String[] args) {
        //1.创建MyRunnable类的对象
        MyRunnable mr = new MyRunnable();

        //2.开启线程,执行线程任务
        Thread t = new Thread(mr);
        t.start();//开启线程,自动执行MyRunnable对象的run方法

        Thread t2= new Thread(mr);
        t2.start();


        //3.使用lambda表达式提供线程任务
        Thread t3 = new Thread(()->{
            for (int i = 0; i < 1000; i++) {
                System.out.println("天王盖地虎,我是第一..."+i);
            }
        });
        t3.start();

    }
}

注意: 继承Thread的方式,线程任务和线程耦合死了,不灵活,所以一般使用第二种

2.2.3 实现Callable接口

可以让当前线程获取子线程执行的结果

java 复制代码
/*
    Callable接口是jdk提供的用于规范线程任务的接口 call,可以返回结果
 */
public class MyCallable implements Callable<Long> {
    //线程任务
    @Override
    public Long call() throws Exception {
        long sum = 0;
        for (int i = 0; i < 100000; i++) {
            sum+=i;
        }
        System.out.println("MyCallable.run 输出: "+sum);
        return sum;
    }
}




public class Test {

    public static void main(String[] args)throws Exception {
        //1.创建MyCallable对象
        MyCallable mc = new MyCallable();

        //2.创建FutureTask类,包装一个Callable
        //FutureTask是Runnable接口的实现类
        //FurureTask中提供了一个方法 get方法,用于获取未来任务执行完毕后返回的结果
        FutureTask<Long> ft = new FutureTask<>(mc);

        //2.创建线程,把线程任务交给线程执行
        Thread t = new Thread(ft);

        t.start();

        //获取子线程执行的结果, 一定是在开启线程之后获取
        Long result = ft.get();//获取子线程的任务,如果子线程没有返回结果,那么我就一直等等等(阻塞),直到返回结果为止!
        System.out.println("子线程运算的结果为: "+result);
    }
}

2.3 线程安全

2.3.1 前提

Thread中常见的API

Thread():创建普通的线程

Thread(Runnable r): 创建线程的同时指定线程任务

Thread(Runnable r,String name): 创建线程的同时指定线程任务,并且指定线程的名字

Thread.currentThread(): 获取正在执行的线程对象

String getName(): 获取线程的名字

java 复制代码
//书写卖票的任务
public class SaleMovieTicketRunnable implements Runnable {
    //票的总量
    private int tickets = 100;

    @Override
    public void run() {
        //模拟卖票的代码
        while (true) {
            if (tickets > 0) {
                System.out.println(Thread.currentThread().getName()+" 卖出第" + tickets + "张票...");
                //票数减少
                tickets--;
            } else {
                //结束卖票
                break;
            }
        }
    }
}


public class Test {
    public static void main(String[] args) {
        //真正的卖票 多窗口同时卖票
        SaleMovieTicketRunnable r = new SaleMovieTicketRunnable();

        //创建两个线程,模拟卖票
        Thread t1 = new Thread(r, "窗口1");
        t1.start();

        Thread t2 = new Thread(r, "窗口2");
        t2.start();

    }
}

线程安全问题:

提前:
	1.多线程
	2.多个线程操作共同的资源
	3.多个线程对共同的资源做增删改的操作
本质:
	多线程的调用是争抢调度
2.3.2解决线程安全问题

同步(加锁)

同步代码块:

​ 格式:

​ synchronized(锁){

​ 保证只能有一个线程执行的代码

​ }

锁: 可以是任何java对象, 多个线程如果要达到同步的效果,这多个线程必须使用的是同一把锁

java 复制代码
//书写卖票的任务
public class SaleMovieTicketRunnable implements Runnable {
    //票的总量
    private int tickets = 100;
    //private Object lock = new Object();
    @Override
    public void run() {
        //模拟卖票的代码
        while (true) {
            /*synchronized (lock){
                if (tickets > 0) {
                    System.out.println(Thread.currentThread().getName()+" 卖出第" + tickets + "张票...");
                    //票数减少
                    tickets--;
                } else {
                    //结束卖票
                    break;
                }
            }*/
            synchronized (this){
                if (tickets > 0) {
                    System.out.println(Thread.currentThread().getName()+" 卖出第" + tickets + "张票...");
                    //票数减少
                    tickets--;
                } else {
                    //结束卖票
                    break;
                }
            }
        }
    }
}

同步方法:

格式:

​ public synchronized 返回值类型 方法名(参数列表){

​ 代码

​ }

锁默认是this

java 复制代码
//书写卖票的任务
public class SaleMovieTicketRunnable implements Runnable {
    //票的总量
    private int tickets = 100;

    @Override
    public void run() {
        //模拟卖票的代码
        while (true) {
            if (sale()){
                break;
            }

        }
    }

    //同步方法: 锁是this
    //返回值代表票有没有卖完
    public synchronized boolean sale(){
        if (tickets > 0) {
            System.out.println(Thread.currentThread().getName()+" 卖出第" + tickets + "张票...");
            //票数减少
            tickets--;
            return false;
        } else {
            //结束卖票
            return true;
        }
    }

}

2.4 线程池

概念: 使用一个容器(数组|集合),存放了多个线程对象

作用: 提高线程的使用率, 避免创建过多的线程

2.4.2 线程池的使用

1.创建线程池

ThreadPoolExecutor:

java 复制代码
ThreadPoolExecutor(       int corePoolSize,//核心线程的个数
                          int maximumPoolSize,//最大的线程个数
                          long keepAliveTime,//线程的最大存活时间
                          TimeUnit unit,//时间单位
                          BlockingQueue<Runnable> workQueue,//任务队列
                          ThreadFactory threadFactory,//线程工厂:创建线程对象
                          RejectedExecutionHandler handler)//拒绝策略
    

2.把线程任务交给线程池

java 复制代码
public class Test {

    public static void main(String[] args) {
        //创建线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                4,//核心线程数量
                6,//最大线程数量
                10,//最大存活时间
                TimeUnit.MINUTES,//时间单位
                new ArrayBlockingQueue<>(3),//任务队列
                Executors.defaultThreadFactory(),//线程工厂
                //new ThreadPoolExecutor.AbortPolicy()//拒绝策略  抛弃任务,报错
                //new ThreadPoolExecutor.DiscardPolicy()//拒绝策略  抛弃任务
                new ThreadPoolExecutor.CallerRunsPolicy()//拒绝策略, 抛弃任务,那个线程提交的任务,该线程执行这个任务

        );

        //2.把任务交给线程池 submit(Runnable r)
        for (int i = 0; i < 10; i++) {
            executor.submit(()->{
                System.out.println(Thread.currentThread().getName()+" 我是你大爷...");
            });
        }

        //关闭线程池
        //executor.shutdown();
    }
}

2.5 java中的异常

2.5.1 概念

​ 程序发生了不正常的现象

​ jdk提供了大量的XxxException类,用于描述不同类型的异常情况

​ 异常的继承体系:

​ Throwable(类):

​ Error(类): 严重的错误(程序员无法通过修改代码解决)

​ Exception(类): 因为程序员代码书写的问题,导致异常的出现

​ RuntimeException(类): 运行时异常

​ 很多的子类

​ 很多的其它子类: 编译期异常

java 复制代码
public class Demo {
    public static void main(String[] args) {
        //int i = 1/0;//一旦程序发生了不正常的现象,代码不往后走了 ArithmeticException
        //System.out.println(i);

        //String s = null;
        //System.out.println(s.length());//NullPointerException

        //int[] arr = {1,2,3};
        //System.out.println(arr[5]);//ArrayIndexOutOfBoundsException

        A a = new B();
        C c = (C)a;//ClassCastException
        System.out.println(c);

    }
}
class A{

}

class B extends A{

}

class C extends A{

}

2.5.2 异常的产生

throw new XxxException("原因");

java 复制代码
public class Demo2 {

    public static void main(String[] args) {
        /*int[] arr = null;
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));*/

        /*DateTimeFormatter df = DateTimeFormatter.ofPattern("你大爷");
        LocalDateTime date = LocalDateTime.parse("2022-01-01 01:01:01", df);//DateTimeParseException
        System.out.println(date);*/

        printHelloWorldN(-1);
    }

    public static void printHelloWorldN(int n) {
        //合法性校验
        if (n <= 0) {
            //System.out.println("参数不合法: " + n + " 必须大于0!");
            throw new RuntimeException("参数不合法: " + n + " 必须大于0!");
        }

        for (int i = 0; i < n; i++) {
            System.out.println("HelloWorld~");
        }
    }
}
2.5.3 异常的处理

throw new XxxException("原因"):产生了异常, 并且把异常抛给调用者

jvm的默认处理:

​ 1.在控制台输出异常的信息

​ 2.停止程序的运行

程序员手动处理:

​ 1.我不处理,我往上抛,抛给我的调用者

​ throws 异常类名

​ 2.我处理了,不再往上抛了

java 复制代码
public class Demo04 {

    public static void main(String[] args)  {
        print();
    }

    //抛出处理
    public static void print() {
        /*
            try..catch

            try{
                可能产生异常的代码
            }catch(XxxException  xxx){//发生了XxxException我就处理,否则不处理
                异常发生后的处理方案
            }
         */
        try {
            System.out.println("aaaaaaa");
            printHelloWorldN(2);//try中一旦产生了异常,那么try中后续的代码将不执行,直接去执行catch代码块
            System.out.println("bbbbbbb");
        }catch (RuntimeException exception){
            System.out.println("处理方案....");
        }

    }

    public static void printHelloWorldN(int n) {
        System.out.println("ccccccc");
        //合法性校验
        if (n <= 0) {
            //System.out.println("参数不合法: " + n + " 必须大于0!");
            throw new RuntimeException("参数不合法: " + n + " 必须大于0!");
        }
        System.out.println("ddddddd");

        for (int i = 0; i < n; i++) {
            System.out.println("HelloWorld~");
        }
    }
}

2.5.4 编译器异常和运行时异常

Throwable(类):

​ Error(类): 严重的错误(程序员无法通过修改代码解决)

​ Exception(类): 因为程序员代码书写的问题,导致异常的出现 编译期异常

​ RuntimeException(类): 运行时异常

​ 很多的子类

​ 很多的其它子类: 编译期异常

运行时异常: 在编译期间没有提示

编译期异常: 在编译期间有提示, 万一真的出错了,你给我一个解决方案

2.5.5 异常类的常用API
java 复制代码
public class Demo6 {

    public static void main(String[] args) {
        /*int[] arr = null;
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));*/

        /*DateTimeFormatter df = DateTimeFormatter.ofPattern("你大爷");
        LocalDateTime date = LocalDateTime.parse("2022-01-01 01:01:01", df);//DateTimeParseException
        System.out.println(date);*/

        try {
            printHelloWorldN(-1);
        } catch (Exception e) {
            //Exception对象中,封装了发生异常的详细信息,借助于e对象,得到异常的数据
            //获取异常的原因
            String message = e.getMessage();
            System.out.println(message);

            //输出调用栈信息
            e.printStackTrace();

        }

    }

    public static void printHelloWorldN(int n) {
        //合法性校验
        if (n <= 0) {
            //System.out.println("参数不合法: " + n + " 必须大于0!");
            throw new RuntimeException("参数不合法: " + n + " 必须大于0!");
        }

        for (int i = 0; i < n; i++) {
            System.out.println("HelloWorld~");
        }
    }
}
2.5.7 finally关键字

格式:

​ try{

​ }catch(XxxException e){

​ }finally{

​ 代码// 不管有没有发生异常,这些代码必须执行

​ }

java 复制代码
public class Demo7 {

    public static void main(String[] args) {
        try{
            printHelloWorldN(2);
        }catch (RuntimeException r){
            System.out.println("处理方案");
        }finally {
            System.out.println("finally代码块...");
        }

    }

    public static void printHelloWorldN(int n) {
        //合法性校验
        if (n <= 0) {
            //System.out.println("参数不合法: " + n + " 必须大于0!");
            throw new RuntimeException("参数不合法: " + n + " 必须大于0!");
        }

        for (int i = 0; i < n; i++) {
            System.out.println("HelloWorld~");
        }
    }
}
2.5.8 处理异常的注意事项

throws 抛出异常处理还是在try...catch...捕获异常处理中, 声明的异常类型要大于或等于真正抛出的异常类型

java 复制代码
public class Demo08 {

    public static void main(String[] args) {
        /*try{
            method1(10);
        }catch (RuntimeException e){
            System.out.println("处理方案...");
        }*/
        try{
            method1(-1);
        }catch (Exception e){
            System.out.println("处理方案...");
        }
    }

    public static void method1(int n) throws Exception{
        //合法性校验
        if (n <= 0) {
            //System.out.println("参数不合法: " + n + " 必须大于0!");
            throw new Exception("参数不合法: " + n + " 必须大于0!");
        }

        if (n>5){
            throw new IOException("IO异常...");
        }

    }
}
2.5.9 自定义异常

jdk提供的异常类用于描述不同类型的异常, 它无法描述所有的情况做到见名知意, 自定义异常类用于特殊类型的异常情况

定义类,继承Exception或者RuntimeException即可

java 复制代码
public class ArgumentException extends Exception{

    public ArgumentException(){

    }
    public ArgumentException(String message){
        super(message);
    }
}



public class Demo09 {

    public static void main(String[] args) {
        /*try{
            method1(10);
        }catch (RuntimeException e){
            System.out.println("处理方案...");
        }*/
        try{
            method1(-1);
        }catch (ArgumentException e){
            System.out.println("处理方案...");
        }
    }

    public static void method1(int n) throws ArgumentException{
        //合法性校验
        if (n <= 0) {
            //System.out.println("参数不合法: " + n + " 必须大于0!");
            throw new ArgumentException("参数不合法: " + n + " 必须大于0!");
        }

    }
}

三.网络编程

3.1 网络编程相关概念

概念: 写的程序可以通过网络进行访问

3要素:

​ ip: 设备在网络上的唯一标识

​ 端口: 设备上程序的唯一标识 0~65535

​ 协议: tcp,udp,ip...

​ 网路模型:

​ 应用层 http

​ 传输层 tcp|udp

​ 网络层 ip

​ 数据链路层|物理层

3.2 TCP通信(CS架构)

网络软件的架构:

​ B(browser)/S(server)架构: 开发server服务器程序即可,

​ C(client)/S(server)架构: 开发客户端和服务端

java 复制代码
public class Client {

    public static void main(String[] args) throws Exception{
        //Socket(套接字): 完成两个网络设备之间的连接与通信
        //1.创建对象完成连接 127.0.0.1: 本机回环地址(代表我当前电脑)(localhost)
        Socket s = new Socket("127.0.0.1",8888);

        //2.给服务器发送数据
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        bw.write("今天晚上我们去打台球...");
        bw.flush();
        //bw.close();
        s.shutdownOutput();//我不再发数据了

        //3.获取服务端发送的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        /*String data = br.readLine();
        System.out.println(data);*/
        String data = null;
        while ((data = br.readLine())!=null){
            System.out.println(data);
        }

        s.shutdownInput();//不再读了

        //释放资源,断开连接
        s.close();

    }
}

java 复制代码
public class Server {

    public static void main(String[] args)throws Exception {
        //1.创建对象,绑定端口
        ServerSocket ss = new ServerSocket(8888);
        //2.监听客户端的连接
        Socket s = ss.accept();//一旦有客户端连接,这个方法会返回一个socket对象,跟客户通信

        //3.接收客户端发送数据的代码
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String data = br.readLine();
        System.out.println(data);
        //br.close();

        s.shutdownInput();//我不再读客户端发送的数据了

        //4.服务端给客户端发送数据
        /*BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        bw.write("好哈,老地方,不见不散...");
        bw.newLine();//写出一个换行
        bw.write("记得买烟...");

        bw.newLine();//写出一个换行
        bw.write("记得带水...");
        bw.flush();*/
        PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
        pw.println("好啊,不见不散");
        pw.println("记得买烟...");
        pw.println("记得带水...");
        pw.println("记得带杆...");

        pw.flush();

        s.shutdownOutput();//不再发了

        //释放资源
        s.close();
        ss.close();



    }
}

http://localhost:8888/

3.3 HTTP协议

http概念: hyper text transport protocol: 超文本(不仅可以包含文本,还可以包含视频,音频,图片等多媒体数据)传输协议, 规定数据传输双方的规则

特点:

​ 1.无状态的协议

​ 2.基于TCP实现的高级协议

​ 3.默认端口80

​ 4.一次请求只对应一次响应

请求数据格式:

​ 请求行: GET / HTTP/1.1

​ 请求方式 请求资源路径 协议/版本

​ 请求头: Host: localhost:8888

​ 键值对, 键是http协议规定好的,值可以修改

​ 请求空行: 空行,啥都没有,分隔请求头和请求体

​ 请求体:

​ username=zhangsan&password=123456

响应数据格式:

​ 响应行: HTTP/1.1 200 OK

​ 协议/版本 响应状态码 描述

​ 2xx: 200 成功

​ 3xx: 302 重定向

​ 4xx: 404 浏览器路径写错了或者是参数传递错了或者是请求方式错了...

​ 5xx: 500 服务器发生错误

​ 响应头: Content-Type: image/gif

​ 响应头名字是http协议规定好的, 值可以修改

​ 响应空行: 空行,啥都没有,分隔响应头和响应体

​ 响应体:

​ 服务器给浏览器响应的主体数据

3.4 TCP实现BS架构

java 复制代码
public class Server {

    public static void main(String[] args)throws Exception {
        //1.创建对象,绑定端口
        ServerSocket ss = new ServerSocket(8888);
        //2.监听客户端的连接
        Socket s = ss.accept();//一旦有客户端连接,这个方法会返回一个socket对象,跟客户通信

        //3.接收客户端发送数据的代码
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String data = null;
        while (!(data = br.readLine()).equals("")){
            System.out.println("读取: "+data);//""
        }

        //br.close();

        s.shutdownInput();//我不再读客户端发送的数据了

        //4.服务端给客户端发送数据
        /*BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        bw.write("好哈,老地方,不见不散...");
        bw.newLine();//写出一个换行
        bw.write("记得买烟...");

        bw.newLine();//写出一个换行
        bw.write("记得带水...");
        bw.flush();*/

        PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
        //写响应行
        pw.println("HTTP/1.1 200 OK");
        pw.println("Content-Type: text/html;charset=utf-8");
        pw.println();
        pw.println("<h1 style='color:red'>好啊,不见不散</h1>");
        pw.println("<h2>记得买烟...</h2>");
        pw.println("记得带水...");
        pw.println("记得带杆...");

        pw.flush();
        System.out.println("aaaaaaa");
        s.shutdownOutput();//不再发了

        //释放资源
        //s.close();
        //ss.close();

    }
}

3.5 Tomcat

equals("")){

System.out.println("读取: "+data);//""

}

    //br.close();

    s.shutdownInput();//我不再读客户端发送的数据了

    //4.服务端给客户端发送数据
    /*BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    bw.write("好哈,老地方,不见不散...");
    bw.newLine();//写出一个换行
    bw.write("记得买烟...");

    bw.newLine();//写出一个换行
    bw.write("记得带水...");
    bw.flush();*/

    PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
    //写响应行
    pw.println("HTTP/1.1 200 OK");
    pw.println("Content-Type: text/html;charset=utf-8");
    pw.println();
    pw.println("<h1 style='color:red'>好啊,不见不散</h1>");
    pw.println("<h2>记得买烟...</h2>");
    pw.println("记得带水...");
    pw.println("记得带杆...");

    pw.flush();
    System.out.println("aaaaaaa");
    s.shutdownOutput();//不再发了

    //释放资源
    //s.close();
    //ss.close();

}

}

### 3.5 Tomcat
相关推荐
学步_技术6 分钟前
Python编码系列—Python团队开发工作流:高效协作的艺术
开发语言·python·团队开发
柳鲲鹏7 分钟前
编译成功!QT/6.7.2/Creator编译Windows64 MySQL驱动(MinGW版)
开发语言·qt·mysql
三玖诶8 分钟前
如何在 Qt 的 QListWidget 中逐行添加和显示数据
开发语言·qt
JOJO___16 分钟前
Spring IoC 配置类 总结
java·后端·spring·java-ee
追逐远方的梦18 分钟前
二级C语言2023-3易错题
c语言·开发语言
蜗牛学苑_武汉19 分钟前
设计模式之代理模式
java·网络·java-ee·代理模式
一个很帅的帅哥20 分钟前
实现浏览器的下拉加载功能(类似知乎)
开发语言·javascript·mysql·mongodb·node.js·vue·express
极客先躯29 分钟前
java和kotlin 可以同时运行吗
android·java·开发语言·kotlin·同时运行
shiming887933 分钟前
Python数据分析与可视化
开发语言·python·数据分析
kid_sup40 分钟前
C语言错题本
c语言·开发语言