简介:Java教程和实例提供了一个全面的资源集合,包含160多个实例程序来帮助学习者理解和掌握Java编程语言。教程涵盖了Java的基础语法、面向对象编程、异常处理、集合框架、IO流、多线程、网络编程、反射机制、枚举和注解、泛型、Lambda表达式、JDBC、GUI编程以及单元测试和项目管理工具Maven的应用。这些实例不仅涉及理论知识,也重视实践能力的提升,适用于希望提高Java编程技能的学习者。 
1. Java基础语法介绍与实践
Java作为一种广泛使用的编程语言,其基础语法是构建更复杂应用程序的基石。本章将带领读者了解Java的核心语法,并通过实际案例进行操作实践,从而加深对Java编程语言的理解。
1.1 Java程序的结构
Java程序由类(Class)组成,类中包含属性(Fields)和方法(Methods)。每个Java程序必须包含一个公共类,并且该类的名称必须与文件名相匹配。一个简单的Java程序结构如下:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
在这段代码中, public class HelloWorld 定义了一个公共类 HelloWorld ,其中 main 方法是程序的入口点。 System.out.println 是一个输出语句,用于在控制台上打印字符串。
1.2 Java变量与数据类型
Java是一种强类型语言,这意味着每个变量和表达式都有一个确定的类型,而类型检查发生在编译时期。Java的基本数据类型包括整型(如int)、浮点型(如double)、字符型(如char)和布尔型(如boolean)。
int number = 10;
double price = 20.50;
char grade = 'A';
boolean isTrue = true;
在声明变量时,必须指定数据类型,并且每个变量只能声明一次类型。基本数据类型存储的是数据本身的值,而引用类型(如类、接口、数组)存储的是对象的引用。
1.3 控制语句与代码块
控制流语句允许我们改变代码的执行顺序。Java提供了多种控制语句,如条件语句(if-else、switch-case)和循环语句(for、while、do-while)。代码块是由一对大括号 {} 包围的代码集合,定义了一个作用域,变量在这个作用域内声明,仅在此代码块内可见。
if (number > 0) {
System.out.println("Positive Number");
} else {
System.out.println("Non-positive Number");
}
for (int i = 0; i < 10; i++) {
System.out.println("Counting: " + i);
}
以上代码演示了使用条件语句和循环语句的基本用法。对于控制流的更复杂应用,我们将在后续章节中进行详细探讨。
通过本章的介绍,我们已经对Java的基础语法有了一个初步的了解。随着后续章节内容的深入,我们将不断实践这些基础知识,并逐步构建起强大的Java编程能力。
2. 面向对象编程概念与技巧
2.1 类与对象
2.1.1 类的定义和对象的创建
在Java中,类(Class)是创建对象的模板或蓝图。类定义了一组属性和方法,这些属性和方法共同描述了类的对象的特征和行为。对象则是类的实例,每个对象都有自己的状态和行为。
类的定义:
public class Car {
// 属性(成员变量)
private String make;
private String model;
private int year;
// 方法
public void start() {
System.out.println("The car is starting.");
}
// 构造方法
public Car(String make, String model, int year) {
this.make = make;
this.model = model;
this.year = year;
}
// Getter和Setter方法
public String getMake() {
return make;
}
public void setMake(String make) {
this.make = make;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
}
对象的创建和使用:
public class Main {
public static void main(String[] args) {
// 创建Car类的一个对象
Car myCar = new Car("Toyota", "Corolla", 2020);
// 调用对象的方法
myCar.start();
// 访问对象的属性
System.out.println("Make: " + myCar.getMake());
System.out.println("Model: " + myCar.getModel());
System.out.println("Year: " + myCar.getYear());
}
}
在这个例子中,我们定义了一个 Car 类,包含 make 、 model 和 year 三个属性,以及 start() 一个方法。此外,我们还提供了一个构造方法来初始化对象,以及对应的getter和setter方法来访问和修改对象的属性。在 Main 类的 main 方法中,我们创建了 Car 类的一个实例,并调用了它的方法和访问了它的属性。
2.1.2 类与对象的关系和区别
关系: - 类是对象的模板,对象是类的实例。 - 类是抽象的,对象是具体的。 - 一个类可以创建多个对象,它们都拥有类的属性和方法,但每个对象都有自己的属性值。
区别: - 类描述了一类事物的共同属性和行为,是抽象的;对象是类的具体实例,是实际存在的。 - 类的定义不会分配内存空间,对象的创建会分配内存空间。 - 类是静态的定义,对象是动态的实例。
2.2 封装、继承和多态
2.2.1 封装的基本概念和实现方式
封装是面向对象编程的一个重要原则,它指的是将对象的状态(属性)隐藏起来,通过定义公共的方法来访问和修改这些状态。这样做可以保护对象内部状态不被外部随意访问和修改,从而保证了对象内部数据的完整性和安全性。
实现封装的方法: - 使用私有(private)访问修饰符来修饰类的属性。 - 提供公共(public)的getter和setter方法,用于访问和修改私有属性。
public class Person {
private String name; // 私有属性
public Person(String name) {
this.name = name;
}
// Getter方法
public String getName() {
return name;
}
// Setter方法
public void setName(String name) {
this.name = name;
}
}
在这个例子中, Person 类有一个私有属性 name 。外部代码不能直接访问 name 属性,而必须通过 getName() 和 setName() 方法来获取和设置它的值。这样就实现了对 name 属性的封装。
2.2.2 继承的机制和多态的表现
继承是面向对象编程的另一个核心概念。它允许创建一个新类,这个新类继承了另一个类的属性和方法,同时还可以扩展自己的功能。继承机制提高了代码的可重用性,也便于对代码的维护和管理。
继承的机制: - 通过使用 extends 关键字,可以创建一个类的子类。 - 子类继承父类的属性和方法,同时可以添加自己的属性和方法。
public class Employee extends Person {
private String department;
public Employee(String name, String department) {
super(name); // 调用父类的构造方法
this.department = department;
}
// Getter和Setter方法
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
在这个例子中, Employee 类继承了 Person 类。它有自己的属性 department ,并可以调用 Person 类的构造方法和方法。
多态的表现: - 多态允许我们使用一个父类的引用来指向一个子类的对象。 - 根据对象的实际类型,调用相应的方法。
public class Main {
public static void main(String[] args) {
Person person = new Person("Alice");
Employee employee = new Employee("Bob", "IT");
// Person类引用指向Employee类对象
person = employee;
// 多态:调用的是Employee类的getName()方法
System.out.println(person.getName()); // 输出 "Bob"
}
}
在这个例子中, Main 类的 main 方法中创建了 Person 和 Employee 类的对象,并将 Employee 对象赋值给 Person 类型的引用。当我们调用 getName() 方法时,实际上调用的是 Employee 类中重写的 getName() 方法,这就是多态的体现。
2.2.3 继承与组合的对比分析
继承和组合是面向对象编程中两种重要的代码复用方式。它们各自有适用的场景和优缺点,合理选择可以提高代码的设计质量。
继承的特点: - 继承表示“是一个”(is-a)关系。 - 子类是父类的一种特殊形式,它具备父类的所有属性和行为。 - 继承可以创建出专门的子类。
组合的特点: - 组合表示“有一个”(has-a)关系。 - 类通过使用其他类的对象作为其成员变量来实现复杂的功能。 - 组合提供了更高的灵活性和更低的耦合度。
public class Engine {
public void start() {
System.out.println("Engine is starting...");
}
}
public class Car {
private Engine engine;
public Car() {
engine = new Engine();
}
public void startCar() {
engine.start(); // 组合使用Engine类的方法
System.out.println("Car is starting...");
}
}
在这个例子中, Car 类通过组合使用了 Engine 类的对象。 Car 对象通过 Engine 对象的方法启动发动机,这种方式就是组合。相比之下,如果我们使用继承,那么 Car 类将会扩展 Engine 类,变成 Car 是 Engine 的一种特殊形式。
继承和组合各有优缺点,继承容易实现且可以保持方法的一致性,但会增加类之间的耦合度;而组合提供了更高的灵活性,可以降低类之间的耦合度,但实现起来相对复杂。在实际开发中,应当根据具体需求和设计原则来选择合适的实现方式。
3. Java异常处理机制详解
3.1 异常类的层次结构
Java 异常处理机制是 Java 语言中非常重要的特性之一,它使得程序能够处理运行时的错误和异常情况。了解异常类的层次结构是掌握异常处理机制的基础。
3.1.1 Java异常体系概览
Java 中所有的异常都是 Throwable 类的实例,而 Throwable 类是 Error 和 Exception 的父类。Error 用来表示严重的错误,这些错误通常是不可恢复的,例如虚拟机错误(OutOfMemoryError)等。Exception 则是程序可以处理的异常,我们通常说的异常处理主要指的是 Exception 类型的异常。
在 Exception 类下,可以细分为两类异常:checked exception 和 unchecked exception。checked exception 是编译器需要检查的异常,如 IOException。unchecked exception 包括运行时异常(runtime exception)和错误(error),它们不被编译器强制检查,如 ArithmeticException。
3.1.2 常见的异常类介绍
- IOException:表示在输入输出过程中遇到的异常情况,如打开不存在的文件、读写错误等。
- SQLException:在进行数据库操作时可能会抛出的异常,如 SQL 语法错误、连接失败等。
- NullPointerException:当尝试访问 null 对象的成员变量或方法时会抛出此异常。
- ArithmeticException:算术运算时,如整数除以零,会抛出这个异常。
3.2 异常的捕获和处理
3.2.1 try-catch-finally语句的使用
在 Java 中,异常的捕获和处理主要通过 try-catch-finally 语句来实现。try 块中包含可能产生异常的代码,catch 块用来捕获并处理特定类型的异常,finally 块中的代码无论是否发生异常都会执行。
try {
// 可能产生异常的代码
} catch (IOException e) {
// 处理IOException类型的异常
} catch (Exception e) {
// 处理其他类型的异常
} finally {
// 无论是否发生异常都会执行的代码
}
逻辑分析: - 代码首先尝试执行 try 块中的语句。 - 如果 try 块中的任何语句抛出了 catch 中指定的异常类型,则执行相应的 catch 块。 - 如果 try 块中抛出了一个异常,但是没有 catch 块来捕获它,则异常会被传递到方法的调用者。 - finally 块无论 try 块中的代码是否抛出异常都会执行。它是用来执行一些清理工作,比如关闭文件流或数据库连接。
3.2.2 自定义异常类和抛出异常
Java 允许我们通过继承 Exception 或其子类来创建自定义异常类。这通常用于设计复杂的业务逻辑,需要明确区分不同类型的异常。
public class MyCustomException extends Exception {
public MyCustomException(String message) {
super(message);
}
}
逻辑分析: - MyCustomException 类继承了 Exception 类,它通过构造函数接收一个字符串作为异常信息。 - 在业务逻辑中,你可以通过 throw 关键字来抛出这个异常。
public void myBusinessMethod() throws MyCustomException {
if (/* some condition */) {
throw new MyCustomException("业务逻辑异常");
}
}
逻辑分析: - myBusinessMethod 方法使用了 throws 关键字声明了它可能抛出的异常类型 MyCustomException。 - 在方法体内,如果某些条件满足(此处为示例条件),就抛出 MyCustomException 异常。
通过自定义异常和标准异常的结合使用,开发者可以更精确地控制程序的异常流,让程序的错误处理更加清晰和专业。
4. Java集合框架的使用方法
4.1 集合框架概述
4.1.1 集合框架的基本结构
Java集合框架(Java Collections Framework)是一系列接口、实现类和算法的集合,它提供了一套标准的方法来操作和处理集合数据。集合框架的目的是为了更好地存储和操作对象群组。
集合框架的基本结构由以下几个部分组成:
- 接口:为集合对象定义操作规范。
- 实现类:根据接口规范实现具体功能。
- 算法:对集合进行排序、搜索和其他操作。
其中,核心接口包括 Collection (单个元素集合)、 Map (键值对集合)等。而主要的实现类,例如 ArrayList 、 LinkedList 、 HashSet 、 HashMap 等,提供了具体的数据结构来存储和管理集合对象。
4.1.2 集合框架中接口与实现类的关联
集合框架中的接口与实现类之间存在清晰的层次关系和继承关系。接口定义了方法的签名,而实现类则提供了这些方法的具体实现。例如:
-
List接口定义了有序集合的操作,ArrayList和LinkedList都实现了此接口。 -
Set接口定义了不包含重复元素的集合,HashSet和LinkedHashSet提供了不同的实现方式。 -
Map接口则定义了键值对集合的操作,HashMap和TreeMap是其常见的实现。
通过了解这些接口和实现类的关系,开发者可以更有效地选择和使用适合特定需求的集合实现。
4.2 List、Set与Map的使用
4.2.1 List集合的操作方法
List 是一个有序的 Collection 接口,它允许重复的元素。 List 的主要实现类有 ArrayList 和 LinkedList 。
以下是一个使用 ArrayList 的示例代码:
import java.util.ArrayList;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
// 创建ArrayList实例并添加元素
List<String> list = new ArrayList<>();
list.add("Java");
list.add("is");
list.add("Awesome");
// 输出ArrayList内容
System.out.println(list);
// 获取和修改元素
System.out.println(list.get(1)); // 输出: is
list.set(1, "very");
System.out.println(list);
// 删除元素
list.remove(0);
System.out.println(list);
}
}
ArrayList 提供了灵活的动态数组实现,适合频繁随机访问元素。而 LinkedList 提供了双端队列和列表的实现,适合频繁的元素插入和删除操作。
4.2.2 Set集合的特性及应用
Set 是一个不允许重复元素的 Collection 接口,适合用于表示数学中的集合概念。
主要实现类 HashSet 通过哈希表实现,提供了快速的查找速度。 LinkedHashSet 则保持了元素插入的顺序。以下是使用 HashSet 的示例:
import java.util.HashSet;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
// 创建HashSet实例并添加元素
Set<String> set = new HashSet<>();
set.add("Java");
set.add("is");
set.add("Awesome");
// 输出HashSet内容
System.out.println(set);
}
}
HashSet 在添加元素时,会调用元素的 hashCode() 方法和 equals() 方法来确保集合中不包含重复元素。
4.2.3 Map集合的键值对管理
Map 接口提供了一种映射机制,它存储键值对并允许快速查找和更新。 HashMap 和 TreeMap 是 Map 接口的两个常用实现类。
以下是一个使用 HashMap 的示例:
import java.util.HashMap;
import java.util.Map;
public class MapExample {
public static void main(String[] args) {
// 创建HashMap实例并添加键值对
Map<String, String> map = new HashMap<>();
map.put("Java", "Programming Language");
map.put("Python", "Programming Language");
map.put("Java", "Most Popular");
// 输出HashMap内容
System.out.println(map);
// 获取和修改键值对
System.out.println(map.get("Java")); // 输出: Most Popular
map.put("Python", "Very Easy");
System.out.println(map);
// 删除键值对
map.remove("Python");
System.out.println(map);
}
}
HashMap 不保证映射的顺序,它使用哈希表来存储键值对,提供快速的查找速度。而 TreeMap 则使用红黑树结构,键值对会被排序,并支持一系列的排序方法。
总结来看,Java集合框架为开发者提供了丰富的数据结构和操作方法,以便于更加高效地管理数据集合。通过理解和掌握其接口和实现类的使用,开发者可以针对不同的应用场景选择最合适的集合类型。
5. Java IO流操作技术
5.1 IO流的基本概念
5.1.1 IO流的分类和功能
在Java中,IO流是用于处理数据传输的机制,它使得程序可以读取和写入数据。Java的IO流系统非常强大,被广泛应用于文件操作、网络通信等领域。IO流主要分为两大类:输入流(Input Streams)和输出流(Output Streams)。
输入流主要用于从源读取数据到程序中,而输出流则将程序中的数据写入到目标。源可以是文件、网络连接,甚至是内存中的数据结构。目标同样可以是文件、网络连接等。
输入流和输出流根据数据的类型,可以进一步分为字节流和字符流。
- 字节流 :字节流处理的是原始的字节数据,是最底层的数据处理方式。在处理文本文件时,字节流不会考虑字符编码问题,直接以字节为单位进行读写。
- 字符流 :字符流则主要用于处理字符数据,它会根据指定的字符编码处理数据,更适合处理文本文件。Java中的
Reader和Writer是字符流的两个抽象基类。
除了基本的分类,Java IO流还提供了一系列的装饰器模式实现(Decorator Pattern),允许在现有流的基础上增加额外的功能,如缓冲(Buffering)、过滤(Filtering)、转换(Converting)等。
5.1.2 字节流与字符流的区别
在Java中,字节流与字符流虽然功能相似,但在处理文本数据时,两者有明显的区别:
-
字节流 :由于字节流是基于字节的,所以它可以不受字符编码的限制处理任何二进制数据。例如,音频文件、视频文件等都可以用字节流来处理。
-
字符流 :字符流则主要针对文本数据,能够处理文本文件中的编码转换。当使用字符流读取文本数据时,流会自动将字节转换为特定编码的字符。相反,在写入文件时,字符流也会将字符转换为字节。
字节流和字符流的选择主要取决于应用场景。对于二进制文件,如图片、音频和视频等,通常使用字节流。对于文本文件,尤其是涉及到字符编码的文本文件,使用字符流可以避免编码错误,提高代码的可移植性。
在Java的IO库中,字节流的基类是 InputStream 和 OutputStream ,而字符流的基类是 Reader 和 Writer 。这些基类定义了一系列标准的方法,如 read() 和 write() ,用于数据的读取和写入。
5.2 文件读写操作实践
5.2.1 文件输入输出流的使用
在Java中进行文件读写操作,可以使用 FileInputStream 和 FileOutputStream 来处理字节数据,使用 FileReader 和 FileWriter 处理字符数据。以下是如何使用这些流进行基本的文件读写操作:
import java.io.*;
public class FileReadWriteExample {
public static void main(String[] args) {
String sourceFile = "source.txt";
String targetFile = "target.txt";
// 文件复制示例 - 字节流
try (FileInputStream fis = new FileInputStream(sourceFile);
FileOutputStream fos = new FileOutputStream(targetFile)) {
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
// 文件复制示例 - 字符流
try (FileReader fr = new FileReader(sourceFile);
FileWriter fw = new FileWriter(targetFile)) {
int c;
while ((c = fr.read()) != -1) {
fw.write(c);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在使用文件流时,通常要确保资源被正确关闭,避免资源泄漏。在上面的例子中,使用了try-with-resources语句,它保证了在try语句块执行完毕后,无论是否发生异常,都会自动关闭流。
5.2.2 文件的复制、追加和转换操作
文件复制操作
前面的例子已经演示了如何使用Java IO流进行简单的文件复制。这里将介绍更高级的复制操作,例如带缓冲的复制。
import java.io.*;
public class AdvancedFileCopy {
public static void copyFileWithBuffer(String source, String destination) throws IOException {
try (FileInputStream fis = new FileInputStream(source);
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream(destination);
BufferedOutputStream bos = new BufferedOutputStream(fos)) {
byte[] buffer = new byte[1024];
int length;
while ((length = bis.read(buffer)) > 0) {
bos.write(buffer, 0, length);
}
}
}
}
在这个例子中,使用了缓冲流 BufferedInputStream 和 BufferedOutputStream 。缓冲流可以减少对底层系统的调用次数,提高文件操作的效率,尤其是在处理大文件时。
文件追加操作
在进行日志记录或其他场景时,我们可能需要向文件末尾追加内容。这可以通过指定构造函数的第二个参数为 true 来实现,如下例所示:
import java.io.*;
public class FileAppendExample {
public static void appendToFile(String filePath, String text) throws IOException {
try (FileWriter writer = new FileWriter(filePath, true)) {
writer.write(text);
}
}
}
文件转换操作
文件转换操作指的是将文件从一种编码转换为另一种编码。以下是如何使用字符流来完成这个任务的示例:
import java.io.*;
public class FileConvertExample {
public static void convertFileEncoding(String sourcePath, String targetPath, String fromEncoding, String toEncoding) throws IOException {
try (FileReader reader = new FileReader(sourcePath, Charset.forName(fromEncoding));
FileWriter writer = new FileWriter(targetPath, Charset.forName(toEncoding))) {
int c;
while ((c = reader.read()) != -1) {
writer.write(c);
}
}
}
}
在上面的例子中, Charset.forName() 方法用于指定字符流使用的具体编码类型。这样可以确保在读取和写入文件时字符编码能够正确转换。
通过本章节的介绍,我们了解了Java IO流的基本概念、分类和功能。接着,通过文件操作的实践,我们学会了如何使用文件输入输出流进行基本的读写操作,以及如何进行文件的复制、追加和转换等高级操作。掌握了这些基础和技能,可以帮助我们在开发中更高效地处理数据输入输出任务。
6. Java多线程编程技巧
Java作为一门面向对象的编程语言,其多线程编程能力是提升应用性能和实现复杂任务并行处理的关键。理解并掌握Java多线程编程的技巧对于每一位Java开发者而言都至关重要。
6.1 线程的创建与运行
6.1.1 实现Runnable接口和继承Thread类
在Java中,创建线程有两种基本方式:通过实现Runnable接口或继承Thread类。每种方式都有其特定的使用场景和优缺点。
实现Runnable接口
这种方式更符合面向对象的设计原则,因为它允许我们在不破坏封装性的前提下,实现多线程。
class MyRunnable implements Runnable {
@Override
public void run() {
// 执行线程代码
System.out.println("This is a thread created by implementing Runnable interface.");
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
通过上面的代码,我们创建了一个实现了Runnable接口的MyRunnable类,并在main方法中实例化了Thread对象,传入了MyRunnable的实例。这样做的好处是可以通过实现同一个Runnable接口实现多个Thread实例。
继承Thread类
直接继承Thread类是另一种创建线程的方法,它更简单直观,但不适合多继承的场景。
class MyThread extends Thread {
@Override
public void run() {
// 执行线程代码
System.out.println("This is a thread created by extending Thread class.");
}
}
public class Main {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
通过继承Thread类,我们创建了MyThread子类,并覆盖了run()方法,然后在main方法中创建了MyThread对象,并调用start()方法启动线程。
6.1.2 线程的状态管理和优先级设置
Java线程有六种状态,分别是NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED。了解这些状态对于管理线程生命周期和调试多线程程序至关重要。
线程优先级可以设置,范围是1(最低)到10(最高)。默认情况下,每个线程都会被分配一个优先级NORM_PRIORITY。
Thread thread = new Thread(new MyRunnable());
thread.setPriority(Thread.MAX_PRIORITY); // 设置线程优先级为最高
thread.start();
6.2 线程同步与通信
6.2.1 同步方法和同步块的使用
在多线程环境中,访问共享资源时常常需要进行同步处理,以避免数据不一致的问题。Java提供了synchronized关键字来实现线程同步。
同步方法
同步方法会锁定整个对象实例,在同一时刻只能由一个线程访问。
class SharedObject {
synchronized public void accessResource() {
// 操作共享资源
}
}
同步块
同步块允许你指定被锁定对象,这样可以提高效率。
class SharedObject {
Object lock = new Object();
public void accessResource() {
synchronized (lock) {
// 操作共享资源
}
}
}
6.2.2 线程之间的协作与通信机制
线程之间可以通过wait()、notify()和notifyAll()方法进行协作,这些方法必须在同步块中调用。
synchronized (lock) {
while (条件不满足) {
lock.wait(); // 等待
}
// 条件满足后,其他线程调用notify()唤醒
lock.notify();
}
6.3 线程池的使用与管理
6.3.1 线程池的基本概念和优势
线程池是一种多线程处理形式,它能够有效地管理线程并减少创建和销毁线程的开销。线程池适用于需要大量线程执行任务的场景,可以有效利用资源并降低系统开销。
6.3.2 线程池的配置和工作原理
Java提供了Executors工具类来简化线程池的创建和管理。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(4); // 创建固定大小为4的线程池
for (int i = 0; i < 10; i++) {
executor.submit(new Task()); // 提交任务
}
executor.shutdown(); // 关闭线程池
}
}
class Task implements Runnable {
@Override
public void run() {
System.out.println("Task executed by thread pool");
}
}
在上面的示例中,我们创建了一个固定大小为4的线程池,并提交了10个任务。每个任务将在某个线程池中的线程执行。
线程池的工作原理是通过管理一组工作线程来执行任务。它根据需要自动创建和回收线程,重用现有的线程来执行提交的任务,从而减少线程创建和销毁的开销,提升性能。
简介:Java教程和实例提供了一个全面的资源集合,包含160多个实例程序来帮助学习者理解和掌握Java编程语言。教程涵盖了Java的基础语法、面向对象编程、异常处理、集合框架、IO流、多线程、网络编程、反射机制、枚举和注解、泛型、Lambda表达式、JDBC、GUI编程以及单元测试和项目管理工具Maven的应用。这些实例不仅涉及理论知识,也重视实践能力的提升,适用于希望提高Java编程技能的学习者。

7193

被折叠的 条评论
为什么被折叠?



