Java-Review

news2024/11/24 8:01:31
题型分值总分分布
简答 5 ∗ 8 ′ 5*8' 58 4 0 ′ 40' 40面向对象、异常处理、多线程、输入输出处理
程序分析和补全 3 ∗ 1 0 ′ 3*10' 310 3 0 ′ 30' 30异常处理、Collection、图形化界面、输入输出处理
编程 2 ∗ 1 5 ′ 2*15' 215 3 0 ′ 30' 30Collections、多线程、图形化界面

“题量多,编程题有点难度。”

第十一章网络编程与第十二章数据库编程考试不涉及,除此之外前十章都有涉及。
本篇文章引用文本中的内容均为yy的原话(原意)。
新增了zaj复习课的内容,由于zaj是课程负责人,所以大概率可以将两张卷子的内容简化到一张卷子。

题目类型推测

大概有3~4个简答题会是面向对象及之前的内容。
后五章一定每章都有一个大题(程序分析和补全 / 编程)。
不排除图形化是程序分析和补全题的可能。

简答(考察可能性较大)

  • Java语言的特点
  • Java语言的执行过程
  • 单例设计模式
  • 抽象类与接口的比较
  • 面向对象的三大特征
  • 线程的互斥与协作是怎么实现的
  • 流的分类

程序分析和补全 / 简答

可能1:

  • A卷:
    程序分析与补全:异常+多线程+输入输出
    编程:Collection+图形化
  • B卷:
    程序分析与补全:异常+Collection+输入输出
    编程:多线程+图形化

可能2:

  • A卷:
    程序分析与补全:异常+Collection+图形化
    编程:Collection+多线程
  • B卷:
    程序分析与补全:异常+Collection+输入输出
    编程:多线程+图形化

附——Java文件及程序结构

对于小型项目和程序,我们一般把程序都写在一个.java文件中,这个.java文件我们通常将其命名为Main.java,这个文件的命名就是我们Java程序运行的入口类,该类必须为public。总结来说每个Java文件中只能有一个public类,而且这个public类的名称必须和文件名相同。在下面这个例子中,该程序的public类是Main,所以这个Java文件只能命名为Main.java。程序进入这个Main类之后,需要继续找执行的入口,也就是main()方法,即固定的public static void main(String[] args),从这个地方开始执行程序。

class Point {
    private int x, y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public String toString() {
        return "<" + x + "," + y + ">";
    }
}
public class Main {
    public static void main(String[] args) {
        ArrayList<Point> s = new ArrayList<>();
        s.add(new Point(2, 1));
        s.add(new Point(1, 1));
        s.add(new Point(2, 2));
        s.add(new Point(1, 2));
        for (Point sett : s) {
            System.out.println(sett.toString());
        }
    }
}

在上面的例子中有两个类,分别是Point和Main,Java在编译时会为每个类都产生一个.class文件,然后寻找对应public类名字的.class文件作为运行的数据接口。
在这里插入图片描述
该程序的文件结构如上图所示,out/production文件夹中存放的是编译生成的.class文件,javaStructure为本项目名称,其下的Main和Point即为两个.class文件。src中存放的是.java文件,在Main.java中共有两个类,分别是Main和Point。

再看下面这个程序,比较一下和上面的有什么不同。

class Main {
    static class Point { // 静态
        private int x, y;
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
        public String toString() {
            return "<" + x + "," + y + ">";
        }
    }
    public static void main(String[] args) {
        ArrayList<Point> s = new ArrayList<>();
        s.add(new Point(2, 1));
        s.add(new Point(1, 1));
        s.add(new Point(2, 2));
        s.add(new Point(1, 2));
        for (Point sett : s) {
            System.out.println(sett.toString());
        }
    }
}

这个程序把Point类也放到了Main中,但是还有一个区别是Point类被设为了静态的。如果不加static的话,Point就是一个实例内部类,但访问实例内部类需要通过其外部内部类的实例,显然不符合我们的编程目的,符合我们要求的是静态内部类。
在这里插入图片描述
该程序的文件结构如上图所示。
所以为了避免使用内部类,最好将类分开定义,Main主类中只写主方法main(),就像第一个程序那样。

第十章——Java输入输出处理

“会有一个单独的题目来考察Java的输入输出。”
“这章主要是三个问题,流的分类和各个流的基本的功能,流的包装,流的基本的操作,read/write方法,包括DataInputStream和DataOutputStream,readInt()、writeInt()等方法都大概了解一下。”

这一章主要需要理清各个类之间的关系,它们分别的作用。详细读一下代码,比较各个代码的异同。

流的概念

流是针对外部I/O读写的一种模式。
对各种外部设备和网络进行数据的输入/输出操作称为I/O处理,Java用流封装对数据的读写操作,提供了对数据序列读/写的统一接口,封装了程序和操作系统的I/O细节。

(简答) ★ ★ \bigstar\bigstar ★★流的分类

  1. 根据数据流的流动方向分类:
    输入流:从数据源读数据到程序的数据流。
    输出流:将数据从程序写到数据宿的数据流。
  2. 根据数据的处理单位分类:
    节点流:从(向)某个特定的数据源读(写)数据的流。
    处理流(过滤流):将某个已存在的流作为自己的数据源或数据宿进行封装和处理。
  3. 根据数据的处理单位分类:
    字节流:数据未经加工,以字节为传输单位。
    字符流:经过一定编码后的数据,以字符为单位读写数据。

字节流

对于字节流,掌握FileInputStream/FileOutputStream、DataInputStream/DataOutputStream、BufferedInputStream/BufferedOutputStream.
在这里插入图片描述

  1. FileInputStream:从某个文件中读数据。
    int read():从输入流中读取一个字节。返回字节值。
    int read(byte[] b):从输入流中读取,写入b。返回实际读取字节数。
    int read(byte[] b, int off, int len):从输入流中读取len个数据,写入b,从索引off开始。返回实际读取字节数。
public class Main {
    public static void main(String[] args) {
        byte[] buf = new byte[25];
        try {
            File f = new File("./src/test.txt");
            FileInputStream in = new FileInputStream(f); // 用文件对象创建文件输入流
            int b;
            while ((b = in.read(buf)) != -1) { // read()读取文件信息
                String s = new String(buf, 0, b);
                System.out.println(s);
            }
            in.close();
        } catch (IOException e) {
            System.out.println("File not found");
        }
    }
}
  1. FileOutputStream:向某个文件中写入数据。
    void write(int b):将指定的整型数据b的低字节写入输出流。
    void write(byte[] b):把字节数组b中的数据写入输出流。
    void write(byte[] b, int off, int len):把字节数组b中从off开始的len个字节写入输出流。
public class Main {
    public static void main(String[] args) {
        byte[] buf = new byte[25];
        try {
            System.out.println("input one line words");
            int b = System.in.read(buf);
            FileOutputStream writefile = new FileOutputStream("./src/1.txt", true);
            writefile.write(buf);
            writefile.close();
        } catch (IOException e) {
            System.out.println("Error" + e);
        }
    }
}
  1. 过滤流FilterInputStream和FilterOutputStream
    字节流FileInputStream类和FileOutputStream类只提供纯字节或字节数组的输入/输出。如果要进行特殊数据的输入/输出,如基本数据类型的输入/输出,则要通过过滤流FilterInputStream类和FilterOutputStream类中的各种子类,如下面要着重介绍的DataInputStream/DataOutputStream和BufferedInputStream/BufferedOutputStream。

(1)DataInputStream与DataOutputStream一般成对出现,先使用DataOutputStream写入数据,然后使用DataInputStream读取数据。

public class Main {
    public static void main(String[] args) throws IOException { // 注意不写try-catch的话就要throws抛出异常
        FileInputStream in = new FileInputStream("./src/1.txt");
        DataInputStream in_data = new DataInputStream(in); // 包装
        FileOutputStream out = new FileOutputStream("./src/1.txt");
        DataOutputStream out_data = new DataOutputStream(out);

        out_data.writeInt(100);
        out_data.writeDouble(123.123);
        out_data.writeUTF("hello 1230");
        out_data.close();

        System.out.println(in_data.readInt());
        System.out.println(in_data.readDouble());
        System.out.println(in_data.readUTF());
        in_data.close();
    }
}

(2)缓冲字节流BufferedInputStream、BufferedOutputStream在基础字节流的基础上建立一个缓冲区,提高字节流处理的效率。

public class Main {
    public static void main(String[] args) {
        byte[] buf = new byte[25];
        try {
            File f = new File("./src/test.txt");
            FileInputStream in = new FileInputStream(f); // 用文件对象创建文件输入流
            BufferedInputStream bufferedInputStream = new BufferedInputStream(in); // 包装了一个缓存,其它没有什么不同
            int b;
            while ((b = bufferedInputStream.read(buf)) != -1) {
                String s = new String(buf, 0, b);
                System.out.println(s);
            }
            bufferedInputStream.close();
        } catch (IOException e) {
            System.out.println("File not found");
        }
    }
}

字符流

对于字符流,掌握InputStreamReader/OutputStreamWriter、FileReader/FileWriter、BufferedReader/BufferedWriter.
在这里插入图片描述

  1. InputStreamReader和OutputStreamReader
    将以字节方式表示的流转换为特定平台上的字符表示的流。
public class Main {
    public static void main(String[] args) throws IOException {
        File f = new File("./src/test.txt");
        FileInputStream in = new FileInputStream(f); // 字节流
        InputStreamReader isr = new InputStreamReader(in); // 转换为字符流
        BufferedReader br = new BufferedReader(isr); // 为了调用BufferedReader的readLine()方法
        System.out.println(br.readLine());
    }
}
  1. FileReader和FileWriter
public class Main {
    public static void main(String[] args) throws IOException {
        String s = "123 endl\r\n 456 endl\r\n";
        FileWriter fw = new FileWriter("./src/test.txt");
        fw.write(s); // 向test.txt中写入字符串s
        fw.close();
    }
}
  1. BufferedReader和BufferedWriter
    在基础字符流的基础上建立一个缓冲区,来提高字符流处理的效率,见1。

“文件顺序访问、随机访问这部分不考,串行化你得看是哪一套试卷,不一定考,要大概了解一下,做一个准备。”

对象的序列化(串行化)

zaj:“自己在自学的时候可以重点去看一下,但是考试的话不在我们的考试范围内。”

两个老师的说法有些不同,猜测zaj具体知道考哪张卷子,所以她说串行化不考。

创建的对象一般情况下,随着生成该对象的程序的终止而结束。但是有时候我们需要将对象的状态保存下来,在需要时将对象恢复。这种对象能记录自己状态以便将来再恢复的能力称为对象的持续性(Persistence)。
对象通过写出描述自己状态的数值来记录自己,这个过程叫对象的序列化(Serialization)。

第九章——多线程

“有一道编程的题目。结合一个算法来实现,比如在多线程环境下计算素数。”
“这章有一个编程,有一个简答。”

线程和进程有什么区别?它们之间的关系是什么?

程序处于执行状态就被称为进程。
在进程中,进程可以创建并管理多个并发的执行序列,每个执行序列被称为一个独立的线程。
一个进程中的所有线程共享相同的地址空间和这个进程所拥有的操作系统资源。

(编程)两种线程的构造方法

  1. 继承Thread类,重写run()方法,在Thread生成对象时调用Thread的start()方法。
class EvenOdd extends Thread {
    private int startNum;
    private int m;
    public EvenOdd(int o1, int o2) {
        startNum = o1;
        m = o2;
    }
    public void run() {
        for (int i = startNum; i <= 10; i += 2) {
            System.out.println("in the " + m + " thread :" + i);
        }
    }
}
public class Main {
    public static void main(String[] args) {
        EvenOdd ot = new EvenOdd(1, 1);
        EvenOdd et = new EvenOdd(0, 2);
        ot.start();
        et.start();
        System.out.println("Main thread done");
    }
}
  1. 实现Runnable接口,重写run()方法,用Thread类的构造函数传递Runnable对象,再调用该对象的start()方法。
class EvenOdd implements Runnable { // 区别
    private int startNum;
    private int m;
    public EvenOdd(int o1, int o2) {
        startNum = o1;
        m = o2;
    }
    public void run() {
        for (int i = startNum; i <= 10; i += 2) {
            System.out.println("in the " + m + " thread :" + i);
        }
    }
}
public class Main {
    public static void main(String[] args) {
        Thread ot = new Thread(new EvenOdd(1, 1)); // 区别
        Thread et = new Thread(new EvenOdd(0, 2));
        ot.start();
        et.start();
        System.out.println("Main thread done");
    }
}

由于Java是单一继承,所以当某个类已继承了别的类,则其无法再继承Thread类,这时需要通过实现Runnable接口来构造线程。

“这部分考察的比较简单,没有考察线程同步的内容(编程)。”
“在简答中会问到,线程同步方法中,互斥和协作是怎么实现的,有什么区别。”

线程的同步机制的目的

同步机制用来保证进程之间执行顺序正确,确保当两个或多个线程要同时访问共享数据时,一次只能有一个线程访问共享数据,保持共享资源的一致性,使线程之间实现协作。

(简答) ★ ★ ★ \bigstar\bigstar\bigstar ★★★线程互斥

在同一时刻只有一个线程可以操作共享资源。
我们用synchronized来描述互斥对象中的互斥方法。在Java中,每个对象都有一个监视器,当一个线程进入监视器的代码块时,就获得了该对象的锁,其他需要执行该锁代码块的线程就只能等待。当一个线程执行完毕后,释放该对象的锁,其他等待该对象的线程就可以进入代码块并重复上述过程。

(简答) ★ ★ ★ \bigstar\bigstar\bigstar ★★★线程协作

通过synchronized只实现了较低层次的互斥同步,解决了共享数据一致性的问题,下面还需要进一步解决线程同步中如何使任务之间可以协调工作的线程协作问题。
Java线程之间协作最简单的方式,是通过继承自Object类的wait()notify()notifyAll()方法来实现线程挂起和唤醒。wait()方法是使线程等待,直到其他线程调用notify()notifyAll()方法唤醒它;notify() 方法会随机唤醒等待中的一个线程并使它竞争锁;notifyAll() 方法会唤醒所有等待中的线程。

线程协作机制:协作机制建立在保证共享资源的一致性的基础上,而Java实现线程协作的其中一个方法是使用wait()notify()/notifyAll()方法。在这种模型中,线程首先需要请求共享对象的锁,如果没有取得锁则进入同步序列等待锁释放,如果取得锁则判断共享对象是否满足操作条件。如果不满足则使用wait()方法阻塞当前进程并进入对象的等待队列,同时释放锁;如果满足则执行相应逻辑,执行完后如果条件发生改变则使用notify()/notifyAll()方法通知所有等待在对象上的线程并释放锁,接收到通知的线程从等待队列离开,进入同步队列等待锁。

(编程)第八章——Collection

“Java的集合部分呢,也有一个编程题目。在AB卷里,不一定能考到。”
“掌握三个接口,Set、List和Map,结合泛型在一起使用。”
“在两套试卷里面,有编程,有简答,集合是和泛型结合在一起进行考察的。”

对于三种不同的集合,要掌握他们的定义、添加元素和遍历,重点掌握ArrayList(包括其排序和查找),Map可不看。

Set

集合里不能放重复对象,不能放基本数据类型,只能放引用数据类型(对象)。
Set有两个具体实现类:无序的HashSet、有序的TreeSet。

TreeSet支持两种排序方式:自然排序和客户化排序,可以将这两种方法对比理解。

  1. 使用自然排序时,只能向TreeSet集合中加入同一类型的对象,并且这些对象必须实现Comparable接口(中的compareTo()方法)。
class Point implements Comparable {
	private int x, y;
	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}
	public String toString() {
		return "<" + x + "," + y + ">";
	}
	public int compareTo(Object obj) {
		if (obj instanceof Point) {
			Point p = (Point)obj;
			return (x * 1000 + y) - (p.x * 1000 + p.y);
		} else {
			return -1;
		}
	}
}
public class Main {
	public static void main(String[] args) {
		Set<Point> s = new TreeSet<> ();
		s.add(new Point(2, 1)); // 向集合中加入元素
		s.add(new Point(1, 1));
		s.add(new Point(2, 2));
		s.add(new Point(1, 2));
		// 遍历方式1:迭代器
		Iterator<Point> it = s.iterator();
		while (it.hasNext()) {
			System.out.println(it.next().toString());
		}
		// 遍历方式2:使用增强for循环(推荐)
        for (Point sett : s) {
            System.out.println(sett.toString());
        }
	}
}
  1. 客户化排序需要自定义一个比较类,其中compare()方法用于比较大小。
class PointCompare implements Comparator<Point> { // 实现Comparator接口
    @Override
    public int compare(Point o1, Point o2) { // 重写compare方法
        return (o1.getX() * 1000 + o1.getY()) - (o2.getX() * 1000 + o2.getY());
    }
}
class Point {
    private int x, y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    int getX() {return x;}
    int getY() {return y;}
    public String toString() {
        return "<" + x + "," + y + ">";
    }
}
public class Main {
    public static void main(String[] args) {
        Set<Point> s = new TreeSet<> (new PointCompare()); // 在新建TreeSet时进行调用
        s.add(new Point(2, 1));
        s.add(new Point(1, 1));
        s.add(new Point(2, 2));
        s.add(new Point(1, 2));
        // 遍历方式1:迭代器
        Iterator<Point> it = s.iterator(); 
        while (it.hasNext()) {
            System.out.println(it.next().toString());
        }
        // 遍历方式2:使用增强for循环(推荐)
        for (Point sett : s) {
            System.out.println(sett.toString());
        }
    }
}

List

List里可以放重复的对象。
List有两个具体实现类:

  1. ArrayList:底层用数组实现,查询效率高
  2. LinkedList:底层用双链表实现,插入与删除效率高
public class Main {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer> ();
        list.add(1);
        list.add(4);
        list.add(3);
        list.add(2);
        // 遍历方式1:利用for循环通过下标访问,只有ArrayList可用下标访问
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i) + " ");
        }
        System.out.println("");
        Collections.sort(list);
        // 遍历方式2:迭代器
        Iterator<Integer> it = list.iterator();
        while (it.hasNext()) {
            System.out.print(it.next() + " ");
        }
        System.out.println("");
        // 遍历方式3:使用lambda表达式
        list.forEach(integer -> System.out.println(integer + " "));
        // 遍历方式4:使用增强for循环(推荐)
        for (Integer integer : list) {
            System.out.print(integer + " ");
        }
    }
}

ArrayList还有一个重点是binarySearch()方法,二分的前提是序列有序。下面用一个Point类来举例其用法。

class Point {
    private int x, y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    int getX() {return x;}
    int getY() {return y;}
}
public class Main {
    public static void main(String[] args) {
        List<Point> list = new ArrayList<>();
        list.add(new Point(2, 2));
        list.add(new Point(1, 1));
        list.add(new Point(1, 2));
        list.add(new Point(2, 1));
        for (Point point : list) {
            System.out.println(point.getX() + " " + point.getY());
        }
        System.out.println();
        Collections.sort(list, ((o1, o2) -> { // lambda表达式自定义排序
            if (o1.getX() != o2.getX()) return o1.getX() - o2.getX();
            else return o1.getY() - o2.getY();
        }));
        for (Point point : list) {
            System.out.println(point.getX() + " " + point.getY());
        }
        System.out.println(Collections.binarySearch(list, new Point(2, 1), ((o1, o2) -> {
            if (o1.getX() != o2.getX()) return o1.getX() - o2.getX();
            else return o1.getY() - o2.getY();
        })));
        // binarySearch有三个参数和一个返回值,分别是要二分的序列、要找的元素、比较方法,返回值是int类型,表示要找的元素的位置
    }
}

Map

Map也有两种具体实现类,HashMap和TreeMap,对应于Set两种具体实现类的名字,HashMap应该是无序的,TreeMap应该是有序的。但在Java8之后,HashMap改用红黑树实现,会按照元素插入时的顺序来维护元素的顺序,也能够保证有序性,但和TreeMap是两种不同的实现结构。所以在考试中不必特意区分HashMap和TreeMap,这两种都是有序的。

public class Main {
    public static void main(String[] args) {
        Map<String, String>  map = new TreeMap<>();
        map.put("4", "Monday");
        map.put("1", "Monday");
        map.put("one", "Monday");
        map.put("2", "Tuesday");
        map.put("3", "Wednesday");
        // 使用lambda表达式遍历map
        for (Map.Entry<String, String> mEntry : map.entrySet()) {
            System.out.println(mEntry.getKey() + " " + mEntry.getValue());
        }
    }
}

“泛型这块考察的内容不是很多,基本上你看完Set这一章节就ok了。”
“泛型主要看看它的原理,考察的重点是集合,不是泛型。”

泛型的实质

允许在定义接口、类时声明类型形参,类型形参在整个接口、类体内可当成类型使用,几乎所有可使用普通类型的地方都可以使用这种类型形参。
Java的泛型就类似C++的模板template。

使用泛型的目的

  1. 类型安全性:通过使用泛型,Java编译器可以在编译时进行类型检查,减少运行时出现的类型转换错误。
  2. 代码重用:使用泛型可以实现通用算法,将数据结构与操作分开,达到更好的代码重用。
  3. 代码可读性:使用泛型增加了代码的命名规范以及代码的易读性,在代码中使用泛型参数名称能够更加清晰地表达代码的意图。
  4. 减少强制类型转换:使用泛型的方式可以减少使用强制类型转换的情况,降低代码的复杂度同时提高代码的可读性。
  5. 提供更好的性能:对于类似 ArrayList 等集合类,使用泛型可以帮助编译器优化代码生成的字节码,从而提高代码的性能。

如何用泛型声明一个类

public class Apple<T> {
	private T info;
	public Apple(T info) {
		this.info = info;
	}
	public static void main(String args[]) {
		Apple<String> a1 = new Apple<>("苹果");
	}
}

(编程)第六章——图形用户界面

“也有一个大题,只考察Swing。”
“今年的题也和这个类似,界面的布局很简单。”
在这里插入图片描述

以上面这个窗口为例,介绍一种使用JPanel和FlowLayout的按行绘制的方法,不继承,直接全部在main中实现,适合横向平铺式普通布局,掌握这个就可以应对考试的简单布局。
在这里插入图片描述
这个窗口可纵向分为四部分,每部分看作一行。我们将整体看作一个JFrame,将其设置为流式布局,即从上到下、从左到右依次放置。为每一行创建一个JPanel(每个JPanel的宽度都大概是窗口JFrame的宽度),JPanel也都是流式布局,然后把每个元素都具体分到某一行,将元素放入对应行的JPanel中,最后将所有JPanel放入整体的JFrame中。

例如第一个红色矩形中,这一行有两个元素,分别是“您的姓名:”和一个输入框。首先创建一个JPanel命名为namePanel,为“您的姓名:”创建一个JLabel,为输入框创建一个JTextField,将namePanel的布局方式设置为流式布局,对齐方式设置为居中对齐,然后各自设置JLabel和JTextField的样式,设置完后加入namePanel中即可。
在第二个黄色矩形中,这一行只有一个元素,就是“您的建议:”这么一个文本。我们首先创建一个JPanel命名为advicePanel,创建一个JLabel,将namePanel的布局方式设置为流式布局,对齐方式设置为向左对齐,设置完JLabel的格式后将其加入advicePanel中即可。

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;

public class Main {
    public static void main(String[] args) {
        /*新建JFrame的步骤
        1.定义JFrame: JFrame jf = new JFrame("title");
        2.设置布局(都用流式布局): jf.setLayout(new FlowLayout());
        3.设置窗口大小: jf.setSize(x, y);
        4.窗口居中显示(可选): jf.setLocationRelativeTo(null);
        5.设置点击右上角关闭即结束程序(可选): jf.setDefaultCloseOperation(3);
        6.设置窗口大小不可更改(可选): jf.setResizable(false);
        *7.设置窗口可见,**必须放在程序最后**: jf.setVisible(true);
         */
        // ********************定义Frame********************
        JFrame jf = new JFrame("GuestBook"); // 设置窗口标题
        jf.setLayout(new FlowLayout()); // 设置为流式布局
        jf.setSize(300, 280); // 窗口大小
        jf.setLocationRelativeTo(null); // 使绘制的画面居中显示(屏幕)
        jf.setDefaultCloseOperation(3); // 默认情况下(0),关闭窗口只隐藏界面,不释放占用的内存,通常情况下应使用3
        jf.setResizable(false); // 无法通过拖动改变画面大小
        Font font = new Font("song", Font.PLAIN, 14); // 定义一个全局字体
        /*为一行新建JPanel的步骤:
        1.定义JPanel: JPanel jp = new JPanel();
        2.设置大小: jp.setPreferredSize(new Dimension(x, y)); 必须用setPreferredSize()
        3.设置流式布局: jp.setLayout(new FlowLayout(FlowLayout.CENTER)); 可居中可靠左等
        4.新建该行中的所有元素:var1,var2,var3等
        5.将该行的所有元素(var1,var2,var3...)加入JPanel: jp.add(var1); jp.add(var2); ...
         */
        // ********************第一行Panel********************
        JPanel namePanel = new JPanel();
        namePanel.setPreferredSize(new Dimension(300, 30)); // Panel占一行,所以宽度可以和窗口相同,高度需要估计一下这一行的元素大概需要多高
        namePanel.setLayout(new FlowLayout(FlowLayout.CENTER)); // 居中显示
        JLabel nameLabel = new JLabel("您的姓名:"); // 字体用JLabel
        nameLabel.setFont(font);
        JTextField nameInput = new JTextField(); // 单行文本框用JTextField
        nameInput.setPreferredSize(new Dimension(100, 20)); // nameInput受namePanel的布局管理器管理,需要使用setPreferredSize()设置尺寸,setSize()无效,下同理
        namePanel.add(nameLabel); // 将这一行的元素都添加到这一行的Panel
        namePanel.add(nameInput);
        // ********************第二行Panel********************
        JPanel advicePanel = new JPanel();
        advicePanel.setPreferredSize(new Dimension(280, 25));
        advicePanel.setLayout(new FlowLayout(FlowLayout.LEFT)); // 由于流式布局有一个默认的上下左右间距为5,这里又是靠左对齐的,
                                                                // 所以如果宽度设为300和窗口一样宽的话,字就会跑出窗口去,所以这里设置宽度280
        JLabel adviceLabel = new JLabel("您的建议:");
        adviceLabel.setFont(font);
        advicePanel.add(adviceLabel); // 将这一行的元素都添加到这一行的Panel
        // ********************第三行Panel********************
        JPanel adviceTextPanel = new JPanel();
        adviceTextPanel.setPreferredSize(new Dimension(280, 110));
        adviceTextPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
        JTextArea adviceText = new JTextArea("请输入:", 5, 15); // 多行文本区域用JTextArea
        adviceText.setPreferredSize(new Dimension(260, 130));
        adviceText.setFont(font);
        adviceTextPanel.add(adviceText);
        // ********************第四行Panel********************
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 30, 5)); // 流式布局上下左右默认间距均为5,这里将水平间距调大,让两个按钮间隔大一些
        JButton submitButton = new JButton("提交");
        submitButton.setFont(font);
        submitButton.setPreferredSize(new Dimension(70, 30));
        JButton resetButton = new JButton("复位");
        resetButton.setFont(font);
        resetButton.setPreferredSize(new Dimension(70, 30));
        buttonPanel.add(submitButton);
        buttonPanel.add(resetButton);
        /* 添加按钮监听事件的步骤:
        1.通过ActionListener接口定义事件event
        2.将事件event加入接收操作的按钮的事件监听队列
        */
        // ********************提交按钮********************
        ActionListener submitListener = e -> {
            JDialog notice = new JDialog(new JFrame(), "notice");
            notice.setVisible(true);
            JLabel noticeLabel = new JLabel("已提交");
            noticeLabel.setFont(font);
            notice.setLayout(new FlowLayout(FlowLayout.CENTER));
            notice.add(noticeLabel);
            notice.setSize(100, 100);
            notice.setLocationRelativeTo(null);
            notice.setDefaultCloseOperation(1);
        };
        submitButton.addActionListener(submitListener);
        // ********************重置按钮********************
        ActionListener resetListener = e -> {
            adviceText.setText("请输入:");
        };
        resetButton.addActionListener(resetListener);
        // ********************将每个Panel都添加到Frame********************
        jf.add(namePanel);
        jf.add(advicePanel);
        jf.add(adviceTextPanel);
        jf.add(buttonPanel);
        // ********************最后设置Frame样式********************
        jf.setVisible(true); // 设置可见 ******必须写在最后******
    }
}

基本控件

“基本控件了解JButton、JLabel、JTextField、JTextArea、JCheckbox、JRadioButton.”

容器

“容器了解JFrame、JDialog、JPanel.”

布局管理器

FlowLayout:流式布局,从左到右从上到下依次填充元素,是JPanel默认的布局方式。
BorderLayout:边界布局,将界面分为东、西、南、北、中五个位置,是JFrame默认的布局方式。

事件处理

由于zaj太过于强调事件处理,所以不排除图形化考察程序分析与补全,补充事件处理流程的可能性,所以需要再多掌握一下事件处理。

事件源:事件产生者。鼠标点击一个按钮产生了事件,那么这个按钮就是事件源。
事件监听器:事件的监听者。是实现了相应的事件监听接口的类的对象,接口中定义了事件处理函数。
事件:某个按钮被按下、鼠标移动等。
Java中处理事件的模型是采用委托处理机制。事件源委托事件监听者负责事件处理。

设计事件监听器类共有三种方法:

  1. 让窗体本身来完成监听器。
  2. 用匿名内部类实现。
  3. 用外部类实现。

内部类在yy的课件里是单独的一章,yy也强调了匿名内部类的重要性,所以这里只介绍2方法。

public class Main {
    public static void main(String[] args) {
        JFrame jf = new JFrame("test");
        jf.setSize(200, 200);

        JButton jb = new JButton("submit");
        jb.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) { // 使用匿名内部类
                jb.setEnabled(false);
            }
        });

        jf.add(jb);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(3);
        jf.setVisible(true);
    }
}

ActionListener是一个接口,addActionListener是一个方法,我们通过重写ActionListener接口中的actionPerformed方法实现了事件监听。但现在匿名内部类的写法大多可用lambda表达式来实现,所以上面的代码和下面的是等价的,下面的写法也就是我们图形化界面的大例子的写法。

public class Main {
    public static void main(String[] args) {
        JFrame jf = new JFrame("test");
        jf.setSize(200, 200);

        JButton jb = new JButton("submit");
        jb.addActionListener(e -> jb.setEnabled(false));

        jf.add(jb);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(3);
        jf.setVisible(true);
    }
}

“绘图这一部分呢,大家简单看一下就行了。主要是去考察一下字体、Graphics类,了解一下draw方法和paint方法,把课件上的例子看一下就行了。”
“能把作业单独完成就完全没有问题了(解一元二次方程)。”

第五章——异常处理

“了解异常处理的结构、异常处理机制。”
“主要是简答和程序分析。”

掌握该异常类图,了解异常的分类与关系。
在这里插入图片描述

(简答)什么是运行时异常?什么是受检查异常?

Java运行时系统对字节码进行解释,并能在程序执行时检测到许多类型的异常,称为运行时异常(Runtime Exception),例如空指针、数组越界、除数为零等。从语法角度上,Java不要求捕获这类异常。
Error是指Java运行时系统的内部错误,属于致命性运行时错误。除了Error类和Runtime Exception类的所有其他异常成为受检查异常(Checked Exception),程序必须对可能发生的这类异常进行处理,否则编译不通过。

(简答)Java的异常处理机制有哪些?

  1. 捕获处理异常
    方法中出现的异常对象将被交给Java运行时系统,运行时系统在方法的调用栈中找到相应异常的捕获处理代码,并把异常对象交给其处理,如果找不到可以捕获异常的代码,程序将终止执行。使用try-catch-finally结构。
  2. 声明异常
    不捕获异常,声明异常只是声明方法有可能抛出的异常,从而让该方法上层调研方法捕获异常。使用throws及throw。

(简答)声明异常的目的是什么?怎样声明一个异常?

声明异常是将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理,那么必须通过throws进行声明,让调用者去处理。
声明异常的方法:修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }

(简答)Java中的异常是如何进行分类的,怎样抛出一个异常?

异常的分类可根据在编译时期还是运行时期去检查异常:

  1. 运行时异常(Runtime Exception):在运行时期检查异常,Java运行时系统对字节码进行解释,在程序执行时检测到许多类型的异常,这类异常可通过适当编程避免,不要求捕获这类异常。
  2. 编译时异常(受检查异常)(Checked Exception):在编译时期就会检查异常,程序必须对可能发生的异常进行处理,否则编译不通过。

Java有两种方法抛出异常:

  1. Java运行时环境自动抛出异常。
  2. 在一定条件下,用户使用throw语句显式抛出异常。

(程序分析)try catch finally结构

public class try_catch_finally {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
		// try不能单独存在,必须结合catch或finally来使用
		// try块中没有异常,会执行finally(如果有)
		// try块中有异常,会执行对应的catch块(如果有),try中异常发生点之后的代码将不会执行
        try {
            // try块中放可能发生异常的代码。
            // 如果执行完try且不发生异常,则接着去执行finally块和finally后面的代码(如果有的话)。
            // 如果发生异常,则尝试去匹配catch块。try异常点之后的代码不会运行。
            int num1 = sc.nextInt(); // 这行代码如果出现异常,那么后面的输出语句就不执行
            int num2 = sc.nextInt();
 			System.out.println(num1 + "\t" + num2);
 			System.out.println(num1 / num2);
            String str = null;
            System.out.println(str.charAt(0));
        } catch (InputMismatchException | NullPointerException e) { 
            // 每一个catch块用于捕获并处理一个特定的异常,或者这个异常类型的子类。Java7中可以将多个异常声明在一个catch中。
            // catch后面的括号定义了异常类型和异常参数。如果异常与之匹配且是最先匹配到的,则虚拟机将使用这个catch块来处理异常。
            // 在catch块中可以使用这个块的异常参数来获取异常的相关信息。异常参数是这个catch块中的局部变量,其它块不能访问。
            // 如果当前try块中发生的异常在后续的所有catch中都没捕获到,则先去执行finally,然后到这个函数的外部caller中去匹配异常处理器。
            // 如果try中没有发生异常,则所有的catch块将被忽略。
            System.out.println("catch块 - try里面发生了异常 - 空指针和输入不匹配异常都走这个catch");
        } catch (ArithmeticException e) {
            e.getMessage();
            System.out.println("算数异常:除数不能为0");
        } catch (Exception e) {
            System.out.println("程序发生未知异常");
        } finally {
            // finally块通常是可选的。
            // 无论异常是否发生,异常是否匹配被处理,finally都会执行。
            // 一个try至少要有一个catch块,否则,至少要有1个finally块。但是finally不是用来处理异常的,finally不会捕获异常。
            // finally主要做一些清理工作,如流的关闭,数据库连接的关闭等。 
            System.out.println("finally块");
        }
        System.out.println("异常捕获之后的代码");
    }
}	

throws

throws仅仅是将函数中可能出现的异常向调用者声明,自己不具体处理。
如果一个方法内部的代码会抛出受检查异常(Checked Exception),而方法自己又没有完全处理掉或并不能确定如何处理这种异常,则javac保证你必须在方法的签名上使用throws关键字声明这些可能抛出的异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理,否则编译不通过。
声明异常的方法:修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }

import java.io.*;
public class ThrowsTest {
    public static void main(String[] args) {
        ThrowsTest t = new ThrowsTest();
        try {
            t.readFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void readFile() throws IOException {
        FileInputStream in = new FileInputStream("hello.txt");
        int b;
        b = in.read();
        while (b != -1) {
            System.out.print((char) b);
            b = in.read();
        }
        in.close();
    }
}

throw

Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要使用throw人工创建并抛出。

public class StudentTest {
    public static void main(String[] args) {
        try {
            Student s = new Student();
            s.regist(-1001);
            System.out.println(s);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}
class Student {
    private int id;
    public void regist(int id) throws Exception {
        if (id > 0) {
            this.id = id;
        } else {
            throw new Exception("您输入的数据非法!");
        }
    }
    @Override
    public String toString() {
        return "Student [id=" + id + "]";
    }
}

第四章——内部类

“内部类没有单独的考察,它是结合我们Java的GUI来一起进行考察的。”
“匿名内部类重点看一下,在多线程的题目、在用户界面编程的题目会碰到。”

内部类是什么

当A类为B类服务时,为了不让外界直接访问到A类,可把这个A类定义在B类的内部,变为内部类。

内部类的分类

实例内部类(成员内部类):如同类的普通成员一样。实例内部类即没有被static修饰的内部类。在创建实例内部类时,必须已经存在外部类的实例。
静态内部类:如同类的静态成员一样。如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static。
局部内部类:局部内部类和局部变量一样,是定义在方法内的类,也不能使用private\public\protected以及static修饰。
匿名内部类:在某些情况下,我们只需要内部类的一个对象,而不需要该类的名字。匿名内部类本身没有构造方法(也不能有),但会调用父类的构造方法。通过匿名内部类实现接口,可以达到隐藏接口的实现的目的。

第三章——面向对象(包括Java概述与基本语法)

(简答) ★ \bigstar Java语言的特点

简单性、面向对象、平台无关性、安全性、多线程、动态性。

(简答) ★ \bigstar Java语言的执行过程

Java程序运行时必须经过编译和运行两个步骤,首先编译后缀为.java的源文件,生成后缀名为.class的字节码文件,Java虚拟机将字节码文件解释执行,并将结果显示出来。

(简答) ★ ★ ★ \bigstar\bigstar\bigstar ★★★面向对象的三大特征

  1. 封装性的目的在于隔离对象的编写者与使用者,使用者无法知晓对象的具体细节,而是通过编写者对对象提供的外部接口来访问对象,降低了软件系统的藕合程度。
  2. 继承性表达了类之间特殊与一般的关系,一般类称为父类,特殊类称为子类,提高了代码的复用性。
  3. 多态性是指类的某个行为具有不同的表现形式,即单一的接口或方法具有不同的动作,Java中的多态包含两种情况:重载与重写(覆盖)。
    重载:多态性在单个类中表现为方法重载;一个类可以有多个名字相同、形参列表不同的方法,在使用时由传递给他们的实参来决定使用哪个方法。
    重写(覆盖):多态性在多个类中表现为继承结构中的方法重写(覆盖);父类和其子类中具有相同的方法头,但用不同的代码实现。

(简答)构造方法的特点

  1. 构造方法的方法名与类名相同。
  2. 构造方法没有返回类型,也不能有void。
  3. 构造方法用new操作符调用,主要作用是初始化对象。
  4. 每个类都至少有一个构造方法,如果没有显式地定义构造方法,Java会自动提供一个缺省的构造方法。

(简答)抽象类的特点

  1. 不能创建实例,即不能new一个抽象类。
  2. 可不含抽象方法,但只要有一个方法是抽象方法,这个类就要定义成抽象类。
  3. 若子类没有实现父类的所有抽象方法,那子类也必须为抽象类。
  4. 构造方法不能都定义为私有,否则不能有子类。
  5. 不能用final修饰,抽象方法必须在子类中才可实现。

(简答)接口的作用

接口提供了一个统一的操作方法名,同样的方法在不同类中可以有不同的具体实现过程,在操作实现了该接口类的对象时采用统一的名字进行调用。

(简答) ★ ★ ★ \bigstar\bigstar\bigstar ★★★抽象类与接口的比较

  1. 语法上,抽象类用关键字abstract class定义,并且可以定义自己的成员变量和非抽象及抽象的成员方法;接口用关键字interface定义,接口内只有公开的静态常量,所有的成员方法都是公开的抽象方法、默认方法和静态方法。
  2. 使用上,抽象类是用来被继承的,一个类只能继承一个父类,但可以实现多个接口,这样可以使用接口实现多重继承,在一定程度上弥补单继承的缺点。
  3. 设计上,抽象类作为父类,与子类之间存在“is-a”关系,即父子类本质上是一种类型;接口只能表示类支持接口的行为,具有接口的功能,因此接口和实现类之间表示的是“like-a”关系。所以在设计上,如果父子类型本质上是一种类型,那父类可设计成抽象类;如果子类型只是想额外具有一些特性,则可以将父类设计成接口,而且这些接口不宜过大,应该设计成多个专题的小接口。这也是面向对象设计的一个重要原则——接口隔离原则:一个类对另一个类的依赖性应建立在最小接口上,不应强迫调用者依赖他们不会使用到的行为,过大的接口是对接口的污染。

类的修饰符和类的成员的修饰符

修饰对象访问修饰符其他修饰符
类(外部)public、缺省final、abstract
语句块缺省static
字段public、protected、缺省、privatefinal、static、transient、volatile
方法public、protected、缺省、privatefinal、abstract、static、native、synchronized

包的相关概念

根据功能的相近性,我们可以将类组织到不同的目录下,这些目录被称为包(package)。
import语句可以引入所需要的类,它可以加载一个包中的所有类或者某个单独的类。
模块(module)是比包更高一个层次的组织单位。

“单例模式是要考的。”

★ ★ \bigstar\bigstar ★★单例设计模式

单例模式是指一个类有且仅有一个实例向整个系统提供。
单例模式设计方案:

  1. 构造方法设为私有权限,防止外界任意调用。
  2. 需要提供一个公有的静态方法获取创建的对象实例。
  3. 创建的唯一对象是被共享且只能被步骤2中的静态方法直接调用,所以需要将其定义为私有的静态对象。
  4. 静态对象的初始化可在外界首次需要对象时在步骤2的方法中调用构造方法创建对象,之后不再创建对象,也可在类的加载阶段初始化。
public class SingleTon {
	private static SingleTon sObj; // 私有且静态
	private SingleTon() {} // 构造方法必须私有
	public static SingleTon getInstance() { // 必须静态
		if (sObj == null) sObj = new SingleTon(); // 首次需要时创建
		return sObj;
	}
class TestSingleTon {
	public static void main(String args[]) {
		SingleTon t1 = SingleTon.getInstance();
		SingleTon t2 = SingleTon.getInstance();
		System.out.printIn(t1 == t2); // 返回true
	}
}

“接口这块大家也要去看一下。”
“简答重点是在面向对象、类和接口、异常处理、集合、IO、线程。”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1220619.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯云服务器怎么样好用吗?腾讯云服务器好用吗?

大家好&#xff01;今天我们要来聊聊腾讯云服务器怎么样&#xff0c;好用吗&#xff1f;对于这个问题&#xff0c;我的答案是非常肯定的——好用&#xff01; 那么&#xff0c;腾讯云服务器究竟好在哪里呢&#xff1f; 首先&#xff0c;它的功能非常强大。它不仅能够提供云存…

2023.11.17-hive调优的常见方式

目录 0.设置hive参数 1.数据压缩 2.hive数据存储格式 3.fetch抓取策略 4.本地模式 5.join优化操作 6.SQL优化(列裁剪,分区裁剪,map端聚合,count(distinct),笛卡尔积) 6.1 列裁剪: 6.2 分区裁剪: 6.3 map端聚合(group by): 6.4 count(distinct): 6.5 笛卡尔积: 7…

2023年中国涂料树脂需求量、市场规模及行业竞争现状分析[图]

涂料用树脂是涂料的主要原材料&#xff0c;是涂料的主要成膜物&#xff0c;且了为涂料成品提供耐醇、耐磨、耐高温、耐高湿、减少涂料在涂装完成后的损耗、保持涂装后外观以及性状的稳定性等功能。 根据生产产品的性状不同&#xff0c;其下游产品&#xff0c;即涂料成品广泛应用…

云网络流量分析工具的关键优势有哪些?

在当今数字化的时代&#xff0c;企业依赖云计算和网络服务以实现高效运营。随着云网络的复杂性不断增加&#xff0c;对网络流量的分析变得至关重要。云网络流量分析工具应运而生&#xff0c;为管理员提供了深入洞察、实时监控的能力。本文将探讨此工具的关键优势以及它们在现代…

君正X2100 读取CHIP_ID

每个处理器会有一个唯一的ID&#xff0c;这个ID可用做产品序列号&#xff0c;或其它。 X21000的CHIP_ID存放于芯片内部的efuse中&#xff0c;efuse是一次性可可编程存储器&#xff0c;初始值为全0&#xff0c;只能将0改为1&#xff0c;不能将1改为0。芯片出厂前会被写入一些信…

修改YOLOv5的模型结构第二弹

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同学的学习圈子 上节说到了通过修改YOLOv5的common.py来修改模型的结构&#xff0c;修改的是模块的内…

2023年【陕西省安全员B证】考试题库及陕西省安全员B证找解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 陕西省安全员B证考试题库是安全生产模拟考试一点通生成的&#xff0c;陕西省安全员B证证模拟考试题库是根据陕西省安全员B证最新版教材汇编出陕西省安全员B证仿真模拟考试。2023年【陕西省安全员B证】考试题库及陕西省…

分布式事务seata的使用

分布式事务介绍 在微服务架构中&#xff0c;完成某一个业务功能可能需要横跨多个服务&#xff0c;操作多个数据库。这就涉及到到了分布式事务&#xff0c;需要操作的资源位于多个资源服务器上&#xff0c;而应用需要保证对于多个资源服务器的数据操作&#xff0c;要么全部成功&…

深度学习_14_单层|多层感知机及代码实现

单层感知机&#xff1a; 功能&#xff1a; 能完成二分类问题 问题&#xff1a; 模型训练采用X*W b训练出模型&#xff0c;对数据只进行了一层处理&#xff0c;也就是说训练出来的模型仅是个线性模型&#xff0c;它无法解决XOR问题&#xff0c;所以模型在训练效果上&#xf…

cookie机制 + java 案例

目录 为什么会有cookie?? cookie从哪里来的&#xff1f;&#xff1f; cookie到哪里去&#xff1f;&#xff1f; cookie有啥用&#xff1f;&#xff1f; session HttpServletRequest类中的相关方法 简单的实现cookie登录功能 实现登录页面 实现servlet逻辑 实现生成主…

【Spring】依赖注入方式,DI的方式

这里写目录标题 1. setter注入在一个类中注入引用类型在一个类中注入简单类型 2. 构造器注入在一个类中注入引用类型在一个类中注入简单类型 3. 依赖注入方式选择4. 依赖自动装配按类型注入按名称注入 5. 集合注入 1. setter注入 在一个类中注入引用类型 回顾一下之前setter注…

Python基础:输入输出详解-输出字符串格式化

Python中的输入和输出是编程中非常重要的方面。 1. 输入输出简单介绍 1.1 输入方式 Python中的输入可以通过input()函数从键盘键入&#xff0c;也可以通过命令行参数或读取文件的方式获得数据来源。 1&#xff09;input()示例 基本的input()函数&#xff0c;会将用户在终端&…

力扣栈与队列--总结篇

前言 八道题&#xff0c;没想到用了五天。当然需要时间的沉淀&#xff0c;但是一天不能啥也不干啊&#xff01; 内容 首先得熟悉特点和基本操作。 栈与队列在计算机底层中非常重要&#xff0c;这就是为什么要学好数据结构。 可视化的软件例如APP、网站之类的&#xff0c;都…

Kotlin原理+协程基本使用

协程概念 协程是Coroutine的中文简称&#xff0c;co表示协同、协作&#xff0c;routine表示程序。协程可以理解为多个互相协作的程序。协程是轻量级的线程&#xff0c;它的轻量体现在启动和切换&#xff0c;协程的启动不需要申请额外的堆栈空间&#xff1b;协程的切换发生在用…

AVL树的底层实现

文章目录 什么是AVL树&#xff1f;平衡因子Node节点插入新节点插入较高左子树的左侧新节点插入较高左子树的右侧新节点插入较高右子树的左侧新节点插入较高右子树的右侧 验证是否为平衡树二叉树的高度AVL的性能 什么是AVL树&#xff1f; AVL树又称平衡二叉搜索树&#xff0c;相…

腾讯云服务器便宜吗?腾讯云服务器怎么买便宜?附优惠链接

首先&#xff0c;咱们来看一下大家最关心的一个问题&#xff1a;“腾讯云服务器便宜吗&#xff1f;”我的答案是&#xff1a;“YES&#xff01;它真的很便宜&#xff01;”比如&#xff0c;轻量2核2G3M服务器&#xff0c;1年只需要88元&#xff0c;是不是很划算&#xff1f;再比…

实例解释遇到前端报错时如何排查问题

前端页面报错&#xff1a; 1、页面报错500&#xff0c;首先我们可以知道是服务端的问题&#xff0c;需要去看下服务端的报错信息&#xff1a; 2、首先我们查看下前端是否给后端传了id: 我们可以看到接口是把ID返回了&#xff0c;就需要再看下p_id是什么情况了。 3、我们再次请…

基于ssm+vue的程序设计课程可视化教学系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

双11背后的中国云厂商:新“标准化”,和调整后的新韧性

降价并不代表一味的压缩自身利润空间&#xff0c;云厂商已经开始向具有更高利润空间的PaaS、SaaS产品腾挪&#xff0c;核心产品在总包占比越来越高。 作者|斗斗 编辑|皮爷 出品|产业家 今年云厂商&#xff0c;全面拥抱双11。 作为中国最大的云计算服务提供商&#xff0…

关于苏州立讯公司国产替代案例(使用我公司H82409S网络变压器和E1152E01A-YG网口连接器产品)

关于苏州立讯公司国产替代案例&#xff08;使用我们公司的H82409S网络变压器和E1152E01A-YG网口连接器产品&#xff09; 苏州立讯公司是一家专注于通信设备制造的企业&#xff0c;他们在其产品中选择了我们公司的H82409S网络变压器和E1152E01A-YG网口连接器&#xff0c;以实现…