当前位置:网站首页 > 云服务教程 > 正文

程序员入门教程电子版(程序员入门教程电子版pdf)



本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本教程出自清华大学,涵盖了Java编程语言的基础知识与核心概念。通过系统学习,读者可以掌握Java在软件开发、Web应用和移动应用中的应用。教程内容全面,从基础语法到面向对象编程,再到异常处理、集合框架、多线程、I/O流、图形界面、网络编程、数据库连接以及Java新特性的详细介绍。学习资源以压缩文件形式提供,包含了教学文档、代码示例和多媒体教学材料。 清華大學java教程

Java是一种广泛使用的面向对象的编程语言,其设计目的是实现跨平台的可移植性和健壮性。Java程序通过编译器转换为字节码,由Java虚拟机(JVM)执行。Java代码被组织在类中,每个类包含数据和操作数据的方法。

 

Java中的数据类型分为基本类型和引用类型。基本类型包括数值型、字符型和布尔型。引用类型则包括类、接口、数组等。变量是程序中数据的容器,必须声明其类型。

 

控制流语句是程序执行的决策点,包括条件判断(if-else)和循环(for, while, do-while)语句。它们允许程序根据条件执行不同的代码路径或重复执行代码块直到满足特定条件。

 

在Java编程世界中,理解上述概念是构建更复杂应用程序的基础。随着章节的深入,我们将探索更多高级主题,如面向对象编程、异常处理、集合框架、多线程以及I/O流等,帮助读者构建起对Java编程的全面认识。

面向对象编程(Object-Oriented Programming,简称OOP)是Java编程语言的核心,它将现实世界的事物抽象为对象,并通过封装、继承和多态这三大特性实现代码的模块化和复用。本章我们将深入探讨这些面向对象编程的关键概念,并介绍如何在Java中实现它们。

2.1 类与对象的构成

2.1.1 类的定义与属性

类是面向对象编程的基础,它定义了一组属性和方法,这些属性和方法组成了对象的状态和行为。在Java中,一个类可以通过关键字 声明,并包含数据字段(变量)和成员方法(函数)。

 

在上述代码中,我们定义了一个 类,它有两个私有属性 和 ,一个构造方法用于创建 对象时初始化这两个属性,以及三个成员方法分别用于获取姓名、获取年龄和打印个人信息。

类的属性通常定义为私有(使用 关键字),这样做的目的是为了封装,只有类自身的方法可以直接访问这些属性,外部代码则需要通过公共方法进行访问和修改,这种方式可以防止外部代码随意更改对象的状态,增强了代码的健壮性。

2.1.2 对象的创建与使用

对象是类的实例,创建对象的过程实际上就是调用类的构造方法的过程。在Java中,创建对象的语法如下:

 

上述代码中,我们使用 创建了一个 类的实例,并将创建的对象引用赋值给变量 。通过这个引用,我们就可以调用 对象的方法了:

 

对象的生命周期从创建开始,到不再被任何引用指向且被垃圾回收器回收结束。在对象的生命周期中,可以多次通过不同的引用调用其方法或者修改其状态。

2.2 继承与多态机制

2.2.1 继承的概念与实现

继承是面向对象编程中的一项重要特性,它允许创建一个新类(子类)继承另一个类(父类)的属性和方法。子类继承父类后,可以扩展新的属性和方法,也可以覆盖(重写)父类的某些方法。

在Java中,继承是通过在子类声明时使用 关键字实现的。例如,我们创建一个 类继承自 类:

 

在这里, 类通过 继承了 类,并添加了一个新的属性 以及一个新方法 来获取学校信息。 类还覆盖了 类的 方法,以提供更详细的学生信息。

2.2.2 方法重写与多态性

方法重写(Override)是子类提供特定于自己的行为的一个实例。通过重写,子类可以改变继承自父类的方法的行为。多态性(Polymorphism)则是一种允许不同类的对象对同一消息做出响应的能力。在Java中,多态通过方法重写以及接口实现实现。

当我们使用父类类型的引用指向子类对象时,根据引用的实际类型调用相应的方法,这体现的就是多态性。

 

在这个例子中,尽管 的类型是 ,但实际指向的是 对象,调用 方法时,Java虚拟机会在运行时确定应该调用哪个类的方法,这里会调用 类重写的方法。

2.3 封装与访问控制

2.3.1 访问修饰符的使用

访问控制是通过使用访问修饰符来实现的,Java中主要有以下四种访问修饰符: 、 (无修饰符)、 和 。

  • :表示私有,只有同一个类中的方法可以访问。
  • :表示包内访问权限,同一个包中的类可以访问。
  • :表示受保护访问,同一个包中的类和所有子类都可以访问。
  • :表示公开访问,任何地方都可以访问。

合理地使用访问修饰符,可以很好地控制类内部的实现细节,以及类的公共接口,增强程序的可维护性和安全性。

2.3.2 封装的意义和实现方式

封装是面向对象的三大特性之一,它的核心思想是将对象的状态和行为封装在对象内部,外部代码只能通过对象提供的公共接口来操作对象。封装可以隐藏对象的内部细节,只暴露必要的操作接口。

在Java中,封装通常是通过将属性定义为私有( ),然后通过公共方法(公共 和 方法)来访问和修改这些属性来实现的。上面的 类已经展示了如何通过封装来保护对象的状态。

封装的实现确保了对象内部状态的完整性,使得对象的使用者不需要关心对象的内部实现细节,只需要知道如何使用对象提供的接口即可。这不仅有助于维护代码的稳定性和可扩展性,也有助于实现业务逻辑的封装。

在第二章中,我们学习了面向对象编程的基础知识,理解了类和对象的构成、继承与多态的实现方法,以及封装的原理和实现方式。掌握这些核心概念对于深入理解Java语言和编写高质量的面向对象程序至关重要。在下一章,我们将探索Java异常处理机制,进一步提升我们应对程序运行中出现的异常情况的能力。

3.1.1 可查异常与非查异常

异常处理是Java语言的一个核心机制,它允许程序在发生错误时提供错误处理的逻辑,保证程序的健壮性和稳定性。在Java中,异常类被组织成层次结构,最顶层是 类。 有两个直接子类: 和 。

类用于表示严重的错误,如 和 ,这些错误通常由外部环境造成且应用程序无法处理,因此开发者不应该捕获 及其子类的实例。

类是所有异常的父类,它又分为两类: (可查异常)和 (非查异常)。 指的是那些派生自 但不是 的异常,如 和 。在编译阶段,Java编译器会强制要求程序处理这些异常,也就是说,如果一个方法可能抛出 ,那么它必须声明这些异常,或者在方法内部捕获并处理这些异常。

相对地, 指的是那些派生自 的异常,如 、 和 。这类异常不需要在方法声明中显式地捕获或抛出,它们通常指示了编程错误,如类型转换错误或数组访问越界。

 

上述代码中 和 方法都可能会抛出 ,因此 方法必须处理(捕获或继续向上抛出)这个可查异常。而 是 的子类,属于非查异常,在这里我们可以直接向上抛出,不需要在方法声明中显示处理。

3.1.2 异常处理的基本语法

Java提供了一套异常处理机制,主要包含 , , 和 关键字。异常处理的基本语法如下:

  • 块用来包围可能抛出异常的代码;
  • 块用来捕获并处理异常;
  • 块中的代码无论是否发生异常都会执行;
  • 语句用来显式抛出异常。
 

一个典型例子如下:

 

在上述代码中,尝试打开一个文件,若文件不存在,则会抛出 。通过 块捕获并处理了这个异常。 块无论是否捕获异常都会执行,其内部通常放置清理资源的代码,如关闭文件流等。

使用异常处理时,需要考虑异常的粒度和业务逻辑,通常建议只对无法恢复的错误使用异常处理机制,并且 块应该尽可能具体地捕获异常类型,以避免屏蔽掉其他重要异常信息。

3.2.1 自定义异常类的创建

Java允许开发者创建自定义异常类,这些异常类通常是 类的子类。创建自定义异常类有助于提供更加具体和清晰的错误信息,更能够贴合应用程序的业务逻辑。自定义异常类应该包含一个无参构造函数和一个带有详细描述信息的构造函数。

 

在上面的自定义异常类 中,我们添加了一个额外的错误码属性 。这样的异常类可以让调用者获得更详细的错误信息,有助于调试和错误恢复。

3.2.2 异常链的构建与意义

异常链是一个异常嵌套另一个异常的结构,其目的是为了记录和传递异常的完整信息。当一个异常发生时,开发者可能会抛出一个新的异常,并将原始异常作为新异常的原因进行传递。这样,异常的调用栈信息不会丢失,外部调用者能够从最上层的异常出发,一层层追溯到最初的异常源头。

Java中构建异常链通常使用 类的构造函数,它允许将一个 作为另一个 的“原因”(cause)。

 

通过异常链,异常处理变得更加灵活和强大。例如,在处理网络请求时,一个服务可能依赖另一个服务,若底层服务抛出了 ,顶层服务可以捕获该异常,并创建一个新的 ,将 作为原因链传递出去。这样,最终的客户端可以接收到一个具体的 ,但仍然可以通过它的原因链追溯到原始的 ,从而进行更精细的错误处理。

3.3.1 异常处理策略

在处理异常时,开发者应该遵循一系列最佳实践,以确保程序的健壮性和可维护性。以下是一些常见的异常处理策略:

  • 记录异常: 对于程序中无法处理的异常,应当记录下来,以供后续分析。记录应当包括异常的类型、错误信息以及可能的堆栈跟踪。
  • 区分异常类型: 根据异常的类型采取不同的处理措施。对于可恢复的异常(如 ),尝试恢复程序;对于不可恢复的异常(如 ),应当终止程序。
  • 异常包装: 在传递异常时,创建自定义异常并提供额外的上下文信息,使得异常的含义更加清晰。
  • 避免空的catch块: 空的catch块会隐藏程序中的错误,应该避免。至少应该记录异常信息。
  • 不要捕获 : 只有在某些特定场景下(比如JVM级别的错误处理)才需要捕获 ,在日常编程中,应当限制捕获的异常类型,以便编译器可以提供编译时检查。
  • 异常不应该用作程序的正常流程: 异常应当仅用于处理异常情况,不应当用来控制程序的正常流程。
 

在上述代码中,我们捕获了 并使用日志记录了异常信息。随后,我们抛出了一个新的 异常,其中包含了原始异常信息。这样,调用者不仅能看到新的异常信息,还可以通过异常链追溯到原始异常。

3.3.2 异常日志记录与分析

异常日志记录是发现和诊断问题的重要手段。良好的异常记录应该包含以下信息:

  • 异常类型: 异常的完整类名。
  • 异常信息: 异常对象提供的详细消息。
  • 堆栈跟踪: 异常发生时的堆栈跟踪信息。
  • 上下文信息: 包括发生异常时的相关业务参数、系统状态等。
  • 时间戳: 异常发生的具体时间。
 

在上面的代码中,我们使用 记录了一个异常。我们获取了 实例,并设置了日志级别为 。记录时,我们传递了异常对象,这样,记录器不仅会记录异常信息,还会附加堆栈跟踪。

异常日志分析包括对异常数据的聚合和趋势分析,这通常在日志管理工具中进行。通过分析异常日志,可以发现系统的问题模式、性能瓶颈或安全威胁,从而制定相应的改进措施。

集合框架是Java编程中不可或缺的一部分,它提供了丰富的接口和实现类,用于存储和操作数据集合。集合框架极大地简化了数据结构的操作和管理,使得开发者能够高效地处理复杂的数据结构问题。

4.1.1 集合框架的结构与接口

集合框架将数据组织为一个有序集合(List),一个无序集合(Set),或者一个键值对映射(Map)。每个接口都定义了一组方法,用于执行不同的操作,如添加、删除、查找和遍历元素。

集合框架的结构图可以表示如下:

 

4.1.2 集合的遍历与转换

遍历集合最常用的是for-each循环,也可以使用迭代器(Iterator),对于Map,还可以使用entrySet、keySet和values方法。集合转换可以使用Java 8引入的Stream API进行。

下面是使用迭代器遍历List的示例代码:

 

4.2.1 List集合的操作与特点

List接口的实现类,如ArrayList和LinkedList,都支持元素的重复添加,它们保持了元素插入的顺序。ArrayList基于数组实现,适合随机访问;而LinkedList基于双向链表实现,适合在链表中间频繁插入和删除操作。

4.2.2 Set集合的唯一性原理

Set接口的实现类,如HashSet和TreeSet,不允许重复的元素。HashSet基于HashMap实现,主要通过对象的hashCode和equals方法判断元素的唯一性;TreeSet通过红黑树实现,可以按照元素的自然顺序或自定义的Comparator进行排序。

4.2.3 Map集合的键值对管理

Map接口的实现类,如HashMap和TreeMap,存储的是键值对。HashMap提供了快速的检索和更新功能,基于散列;TreeMap保持键的排序状态,基于红黑树。

4.3.1 并发集合的使用与性能

为了适应多线程环境,Java提供了java.util.concurrent包,包含了并发集合类,如ConcurrentHashMap和CopyOnWriteArrayList。这些集合在保持线程安全的同时,也提供了较好的性能。

例如,ConcurrentHashMap的使用代码:

 

4.3.2 集合算法与排序

Java集合框架提供了Collections工具类,包含了一系列对集合进行操作的静态方法,例如排序(sort)、搜索(binarySearch)、反转(reverse)等。这些方法可以方便地应用于List集合,提高处理集合的效率。

下面是使用Collections.sort对List进行排序的示例代码:

 

集合框架的深入应用涉及到对集合的扩展理解,比如如何选择合适的集合类型,以及如何优化集合的性能,这些内容将在后续的章节中继续探讨。

5.1.1 线程的创建与生命周期

在Java中,线程是程序执行的最小单元,可以被操作系统调度。一个线程可以执行任意的代码块,包括执行方法的调用。线程的生命周期主要包含新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Terminated)五个状态。

 

在上述代码中,我们创建了一个线程,并在不同的阶段打印出线程的状态。创建线程后,线程处于新建状态。调用 方法后,线程转为就绪状态,等待CPU调度。执行过程中,线程处于运行状态。调用 方法后,主线程将等待该线程死亡,此时线程处于死亡状态。

5.1.2 线程同步与通信机制

在多线程编程中,线程同步是一个非常重要的概念。由于多个线程可能同时访问同一资源,如果不进行适当的同步,就会产生资源竞争和数据不一致的问题。Java通过 关键字提供了线程同步的机制。

 

上面的代码定义了一个简单的计数器类 ,使用 关键字同步了 方法和 方法,确保这些方法在同一时间只有一个线程可以访问。

线程通信机制允许线程之间交换信息, 、 和 是Object类提供的三个方法,它们用于实现线程之间的等待/通知模式。

 

在 方法中,线程执行到 时会释放锁,并进入等待状态。在 方法中,调用 会唤醒所有在该锁上等待的线程。

5.2.1 线程池的原理与配置

线程池是一种多线程处理形式,它能重复使用现有的线程,减少线程创建和销毁的开销。Java中线程池的实现主要依赖于 类和 接口。

 

在这个例子中,我们使用 方法创建了一个固定大小为4的线程池。对于线程池的配置,重要参数包括核心线程数、最大线程数、存活时间以及工作队列类型等。

5.2.2 并发工具类的应用

Java并发包 提供了大量并发工具类,例如 、 、 、 等,这些工具类可以解决不同并发场景下的问题。

 

可以让一组线程互相等待,直到所有线程都到达某个点后,这些线程才会继续执行。这在初始化多个组件并确保它们都准备就绪后才开始工作的场景中非常有用。

5.3.1 多线程在实际应用中的问题

多线程虽然可以提高程序的并发性能,但也带来了诸多问题。常见的问题包括死锁、资源竞争、线程饥饿、活锁、线程安全问题等。例如,在不恰当的使用共享资源时,就会出现资源竞争,导致数据不一致的问题。

5.3.2 解决多线程问题的策略与技巧

解决多线程问题需要对线程同步和通信机制有深入的理解。策略包括:

  • 合理使用线程同步关键字 。
  • 使用 等锁机制来进行更细致的锁控制。
  • 使用 关键字确保共享变量的可见性。
  • 使用并发工具类 、 、 等来简化线程间协作。
  • 注意避免死锁,合理设计锁的获取顺序。

在设计多线程程序时,可以采用一些技巧来提高性能和稳定性,例如尽量减小同步代码块的范围,减少锁争用;使用线程局部变量减少不必要的线程间通信;合理管理线程的生命周期,避免资源浪费和线程泄漏。

通过以上内容,我们已经对Java多线程编程的核心概念和应用有了深入的了解。在实际开发中,多线程编程是一个不断实践和优化的过程,开发者需要根据应用的具体需求来合理设计和调整线程策略。

6.1.1 输入输出流的分类

在Java编程语言中,I/O流是实现数据读写操作的基本机制。流可以被理解为数据在各种输入源和输出目的地之间流动的抽象表现。Java的I/O流主要分为输入流和输出流两大类。

输入流(InputStream和Reader)用于从数据源(如文件、网络连接、内存缓冲区等)读取数据,而输出流(OutputStream和Writer)则用于向数据目的地(如文件、网络连接等)写入数据。

一个关键的概念是字节流(InputStream和OutputStream)和字符流(Reader和Writer)。字节流主要用于处理原始字节数据,如图像或声音文件,而字符流主要用于处理字符数据,特别是文本文件。

6.1.2 字节流与字符流的区别

字节流和字符流之间存在一些重要的区别,这主要源于它们处理数据的方式不同。字节流以8位字节为最小操作单位,而字符流则以16位的Unicode字符为操作单位。

一个典型的字符流是 ,它直接以字符为单位进行读取,适用于文本文件。而字节流如 则可以用来读取二进制文件,比如图片或者音频文件。字符流在内部会根据指定的字符集进行编码转换,而字节流则不进行这种转换,直接以字节为单位进行读写。

字符流提供了方便的缓冲机制,通过 和 来实现。而字节流则通过 和 来实现缓冲功能。

代码示例

以下是一个简单的字节流使用示例,演示了如何使用 读取文件内容,并使用 写入文件内容。

 

在上面的代码中,我们创建了一个 来读取名为 的文件,并创建了一个 来写入内容到名为 的新文件中。注意,我们在读取和写入循环中使用了异常处理来确保程序的健壮性。

6.2.1 缓冲流与转换流的应用

Java I/O流系统为了提高读写效率提供了缓冲机制。缓冲流(BufferedInputStream和BufferedOutputStream、BufferedReader和BufferedWriter)通过内部缓冲区来减少实际的物理读写次数,从而提高整体的I/O性能。

转换流(InputStreamReader和OutputStreamWriter)则起到了桥梁的作用,它们将字节流转换为字符流,这使得我们可以处理基于字符的数据,同时还可以指定字符编码。

6.2.2 文件操作与随机访问

在文件操作方面,Java提供了 类和 类。 是一个功能强大的类,它支持随机访问文件内容。这意味着你可以在文件中任意位置进行读写操作,这在处理大型文件时非常有用。

代码示例

下面的示例代码展示了如何使用 来实现文件的随机读写。

 

在这个示例中,我们首先使用 打开了一个名为 的文件,并设置为读写模式。然后,我们将文件指针移动到文件的第50个字节位置,写入了"Hello World!"字符串。接着,我们将文件指针再次移动到相同位置,并读取了数据,最后将读取到的字节转换成了字符串,并打印出来。

6.3.1 套接字编程基础

Java的网络编程能力主要基于 包中的类和接口。套接字(Socket)是网络通信的基本构件,客户端和服务器端都使用套接字来建立连接和传输数据。

在Java中, 类代表客户端套接字,而 类代表服务器端套接字。服务器端在特定端口上监听客户端的连接请求。一旦接收到请求,服务器端便可以通过 对象与客户端进行通信。

6.3.2 实现一个简单的网络通信程序

下面的代码示例展示了一个简单的TCP服务器和客户端的实现。

 
 

在服务器代码中,我们创建了一个 并绑定到端口12345上,使用 方法监听来自客户端的连接请求。当客户端连接时,服务器会读取客户端发送的消息,并向客户端发送响应。

客户端代码创建了一个 来连接到服务器的IP地址和端口号。连接成功后,客户端发送一条消息到服务器,并等待服务器的响应。服务器和客户端都使用 和 来进行数据的读写操作。

以上就是第六章的内容,通过对Java I/O流系统的详细介绍和示例代码的展示,我们可以清晰地理解Java中输入输出流的基本概念,以及如何在实际的网络通信中应用这些流。

Java Swing 是一个用于构建 Java 图形用户界面(GUI)的工具包,它是 Java 的一部分,允许开发者创建丰富的窗口应用程序。

7.1.1 Swing组件与布局管理

Swing 提供了多种组件(widgets),例如按钮、文本框、列表、树形视图等,这些组件能够嵌套到窗口中。组件可以被放置在面板(JPanel)中,而面板可以进一步被放置到窗口(JFrame)中。

布局管理器(Layout Managers)是 Swing 中用于管理组件布局的类,它负责确定组件的大小和位置。常见的布局管理器包括: - :按组件的添加顺序从左到右、从上到下排列。 - :将组件放在五个区域(北、南、东、西和中心)。 - :将容器分成一个网格,每个格子放置一个组件。 - :显示组件的堆叠方式,一次只显示一个组件。 - :最复杂的布局管理器,可以精确控制组件的位置、大小和流。

以下代码演示了如何使用不同的布局管理器:

 

7.1.2 事件处理机制详解

Swing 组件是事件驱动的,这意味着当用户与组件交互时,会触发事件。为了处理这些事件,Swing 使用了观察者设计模式。

事件监听器是一个实现特定监听接口的类实例,它注册到组件上,当事件发生时,该监听器会被通知。例如,一个按钮被点击,就会触发一个 ,需要注册一个 到按钮上处理这个事件。

下面的示例创建了一个按钮并为其注册了一个 :

 

JavaFX 是一个用于构建富客户端应用程序的框架,是 Java 的下一代 GUI 工具包。

7.2.1 JavaFX与Swing的对比

JavaFX 提供了比 Swing 更丰富的组件集合,它允许更复杂的界面设计,并支持现代的图形技术,如硬件加速渲染、CSS 样式和矢量图形。JavaFX 还具有更好的跨平台一致性,因为它的渲染是基于 OpenGL。

7.2.2 JavaFX的核心组件与特性

核心组件包括 , , 和 。 类似于一个窗口, 是 Stage 中的内容容器,而 是场景中可视化的元素。

JavaFX 特性包括: - CSS 样式支持,可以使用 CSS 文件来控制应用程序的外观。 - 动画支持,可以轻松创建复杂的动画效果。 - 矢量图形支持,允许图形和形状缩放而不失真。

下面的 JavaFX 程序创建了一个包含圆形的简单窗口:

 

Java 的网络功能允许开发者编写客户端和服务器端应用程序,与远程计算机进行通信。

7.3.1 网络数据的传输与处理

Java 提供了多种方式用于网络编程,如 类用于建立连接, 包中的流用于数据传输。

下面是一个简单的客户端和服务器端通信的例子:

服务器端代码

``` .ServerSocket; *.Socket;

public class SimpleServer { public static void main(String[] args) throws Exception { int port = 8000; ServerSocket serverSocket = new ServerSocket(port); System.out.println("等待连接...");

 

}

class HandleClient extends Thread { private Socket socket;

 

}

 

7.3.2 基于Java的客户端与服务器端开发

基于 Java 的客户端与服务器端开发涉及到多线程技术,以支持多个客户端同时连接。服务器必须能够处理多个连接请求,并为每个客户端创建一个单独的线程来处理通信。

该部分已经在第五章中有所涉及,在这里我们简单回顾了客户端和服务器端的交互原理。更详细的实现和优化策略将在后续章节中展开。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本教程出自清华大学,涵盖了Java编程语言的基础知识与核心概念。通过系统学习,读者可以掌握Java在软件开发、Web应用和移动应用中的应用。教程内容全面,从基础语法到面向对象编程,再到异常处理、集合框架、多线程、I/O流、图形界面、网络编程、数据库连接以及Java新特性的详细介绍。学习资源以压缩文件形式提供,包含了教学文档、代码示例和多媒体教学材料。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

到此这篇程序员入门教程电子版(程序员入门教程电子版pdf)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • 程序员代码教程(程序员专用代码)2024-12-15 09:36:10
  • 代码网站有哪些(代码教程网站)2024-12-15 09:36:10
  • ad20铺铜教程(ad18铺铜教程)2024-12-15 09:36:10
  • 启动盘u盘制作教程图解(启动u盘制作方法及注意事项)2024-12-15 09:36:10
  • autohotkey怎么用(autohotkey按键教程)2024-12-15 09:36:10
  • cmake编写教程(cmake怎么写)2024-12-15 09:36:10
  • esp8266天气时钟教程(esp8266 oled天气)2024-12-15 09:36:10
  • awvs使用教程kali(awvs安装教程)2024-12-15 09:36:10
  • 程序员入门教程电子版(程序员入门教程电子版下载)2024-12-15 09:36:10
  • 如何安装虚拟机操作系统(如何安装虚拟机操作系统教程)2024-12-15 09:36:10
  • 全屏图片