高级教程
数据结构
- 枚举
- 一种从数据结构中取回连续元素的方式
- 位集合
- 可以单独设置和清楚的位或标志
- 向量
Vector
是一个基于动态数组的集合类
- 栈
- 实现了一个后进先出的数据结构
- 字典
- 定义了键映射到值的数据结构
- 哈希表
- 在用户定义键结构的基础上来组织数据的手段
- 属性
- 通常指的是类和成员变量,用户存储对象的状态信息。
集合框架
- 用户存储、操作和管理数据集合。提供了各种数据结构,包括列表(List)、集合(Set)、映射(Map)等,以满足不同数据处理需求。Java集合框架的目标主要是提供一种通用、高效和灵活的方式来处理数据集合。
- 主要接口和类包括
- Collection接口
- List:有序、允许重复元素的集合,如ArrayList和LinkedList
- Set:无序、不允许重复元素的集合,如HashSet和TreeSet
- Queue:队列接口,通常用户实现先进先出的数据结构,如LinkedList和PriorityQueue
- Map接口
- Map:键值对的集合,用户存储唯一键值对,如HashMap和TreeMap
- 通用集合框架类
- ArrayList:基于动态数组实现的List
- LinkedList:基于双向链表实现的List
- HashSet:基于哈希表实现的Set
- TreeSet:基于红黑树实现的Set,元素有序
- HashMap:基于哈希表实现的Map
- TreeMap:基于红黑树实现的Map,键有序
- HashMap:基于哈希表实现的Map
- TreeMap:基于红黑树实现的Map,键有序
- LinkedHashMap:基于哈希表和双向链表实现的有序Map
- Hashtable:线程安全的Map,较少使用,推荐使用HashMap
- Vector:基于数组实现的List,较少使用,推荐使用ArrayList
- Collection接口
ArrayList
- 提供了一个可变大小的动态数组来存储元素,ArrayList具有自动调整大小、添加、删除和查找元素等优点。
- ArrayList基本操作
- 导入ArrayList类
import java.util.ArrayList;
- 创建ArrayList
ArrayList<String> list = new ArrayList<>();
- 添加元素
list.add("元素1"); list.add("元素2");
- 获取元素
String element = list.get(0); // 获取第一个元素
- 删除元素
//按照索引删除 list.remove(1); // 删除索引为 1 的元素 //按元素值删除 list.remove("元素1"); // 删除值为 "元素1" 的元素
- 修改元素
list.set(0, "新元素"); // 将索引为 0 的元素值设置为 "新元素"
- 查找元素
int index = list.indexOf("元素2"); // 获取值为 "元素2" 的元素的索引
- 遍历元素
//1.使用迭代器 Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); // 处理元素 } //2.使用增强for循环 for (String element : list) { // 处理元素 } //3.使用普通for循环 for (int i = 0; i < list.size(); i++) { String element = list.get(i); // 处理元素 }
- 总结:ArrayList是一个非常灵活和常用的数据结构,适用于各种需要动态调整大小的场景。由于其底层实现基于数组,因此随机访问元素的性能非常高效。但需要注意,插入和删除操作可能会涉及数组的重新分配,因此在大量插入和删除操作时,性能可能会收到影响。在需要频繁执行插入和删除操作的情况下 ,可以考虑使用LinkedList或其他数据结构。
LinkedList
- 基于双向链表数据结构来存储元素,与ArrayList不同,LinkedList在插入和删除元素时具有很好的性能,但在随机访问元素时性能相对较差。
- 基本操作
- 导入LinkedList类
import java.util.LinkedList;
- 创建LinkedList
LinkedList<String> linkedList = new LinkedList<>();
- 添加元素,与ArrayList不同,LinkedList会在添加元素时执行链表节点的链接操作,而不需要调整数组大小
linkedList.add("元素1"); linkedList.add("元素2");
- 获取元素,支持随机访问元素,但性能可能相对较差
String element = linkedList.get(0); // 获取第一个元素
- 删除元素
linkedList.remove(1); // 删除索引为 1 的元素
- 修改元素
linkedList.set(0, "新元素"); // 将索引为 0 的元素值设置为 "新元素"
- 查找元素
int index = linkedList.indexOf("元素2"); // 获取值为 "元素2" 的元素的索引
- 遍历LinkedList
//1.使用迭代器 Iterator<String> iterator = linkedList.iterator(); while (iterator.hasNext()) { String element = iterator.next(); // 处理元素 } //2.使用增强for循环 for (String element : linkedList) { // 处理元素 } //3.使用普通for循环 for (int i = 0; i < linkedList.size(); i++) { String element = linkedList.get(i); // 处理元素 }
- 总结:LinkedList在需要频繁执行插入和删除操作的情况下性能优越,因此它的底层数据结构是双相链表,这些操作的时间复杂度是O(1).但是,随机访问元素的性能较差,因为需要从头或尾遍历链表节点,时间复杂度是O(n),因此,在不同的场景中,可以根据需要选择ArrayList或LinkedList.
HashSet
- 基于HashMap来实现的,是一个不允许有重复值的集合.
- 基本特点
- 不允许重复
- 允许有null值
- 是无序的,不会记录插入的顺序
- 不是线程安全的
- 实现了Set接口
- 基本操作
- 导入HashSet类
import java.util.HashSet;
- 创建HashSet
HashSet<String> set = new HashSet<>();
- 添加元素
set.add("元素1"); set.add("元素2");
- 删除元素
set.remove("元素1"); // 删除值为 "元素1" 的元素
- 查找元素
boolean contains = set.contains("元素2"); // 检查是否包含值为 "元素2" 的元素
- 遍历HashSet
//1.使用迭代器 Iterator<String> iterator = set.iterator(); while (iterator.hasNext()) { String element = iterator.next(); // 处理元素 } //2.使用增强for循环 for (String element : set) { // 处理元素 }
- 获取HashSet的大小
int size = set.size(); // 获取元素数量
- 清空HashSet
set.clear(); // 清空集合
- 总结:HashSet是一个常用的集合类,特别适用于需要存储唯一元素的情况,以及需要高效地执行元素查找操作的情况。注意,HashSet不维护元素的插入顺序,如果需要有序集合,可以考虑使用TreeSet.此外,如果需要保留元素的插入顺序但不允许重复元素,可以使用LinkedHashSet.
HashMap
- 实现了Map接口,并基于哈希表数据结构来存储键-值对。
- 基本特点
- 键值对:HashMap存储的数据是键值对形式的,每个键都与一个值相关联.
- 不允许重复键:HashMap不允许存储重复的键。如果尝试向HashMap中添加重复键,旧的值将会被新的值替代.
- 无序映射:HashMap不维护键值对的顺序,因此键值对的存储顺序与插入顺序或其他因素无关.
- 高效的查找和插入:由于使用了哈希表,HashMap提供了高效的键查找和插入操作。平均情况下,这些操作的时间复杂度为O(1).
- 基本用法
- 导入HashMap类
import java.util.HashMap;
- 创建HashMap类
HashMap<String, Integer> map = new HashMap<>();
- 添加键值对
map.put("键1", 1); map.put("键2", 2);
- 获取值
int value = map.get("键1"); // 获取键为 "键1" 的值
- 删除键值对
map.remove("键1"); // 删除键为 "键1" 的键-值对
- 查找键
boolean containsKey = map.containsKey("键2"); // 检查是否包含键 "键2"
- 遍历HashMap
//1.使用迭代器 Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Integer> entry = iterator.next(); String key = entry.getKey(); int value = entry.getValue(); // 处理键和值 } //2.使用增强for循环 for (Map.Entry<String, Integer> entry : map.entrySet()) { String key = entry.getKey(); int value = entry.getValue(); // 处理键和值 }
- 获取HashMap的大小
int size = map.size(); // 获取键-值对数量
- 清空HashMap
map.clear(); // 清空映射
lterator
- lterator(迭代器)是Java集合框架中的一个接口,用户遍历集合(Collection)中的元素.迭代器提供了一种统一的方式来迭代访问集合中的元素,而不需要了解集合的具体实现细节.
- 主要方法和示例
- 获取迭代器对象
ArrayList<String> list = new ArrayList<>(); // 添加元素到列表 // ... Iterator<String> iterator = list.iterator();
- 检查是否有下一个元素
while (iterator.hasNext()) { // 有下一个元素时执行操作 }
- 获取下一个元素
while (iterator.hasNext()) { String element = iterator.next(); // 处理元素 }
- 删除当前元素
while (iterator.hasNext()) { String element = iterator.next(); if (condition) { iterator.remove(); // 删除当前元素 } }
- 完整的示例代码
import java.util.ArrayList; import java.util.Iterator; public class IteratorExample { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("元素1"); list.add("元素2"); list.add("元素3"); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String element = iterator.next(); System.out.println(element); if (element.equals("元素2")) { iterator.remove(); // 删除元素2 } } System.out.println("遍历后的集合:" + list); } }
Object
- Object是所有类的父类,Java所有类都继承了Object.位于java.lang包中,因此不需要特别导入就可以使用.
- 主要用途和特性
- 父类
- Object类是Java类层次结构中的根,也就是说,所有的类都直接或间接地继承自Object类。因此,每个对象都继承了Object类的属性和方法。
- toString()方法:用于返回一个描述对象的字符串
@Override public String toString() { return "这是一个自定义对象"; }
- equals()和hasCode()方法:用于对象比较和哈希码生成。通常,我们需要在自定义类中覆盖这些方法,以根据对象的内容来判断相等性和生成哈希码.
@Override public boolean equals(Object obj) { // 比较对象的属性来判断相等性 } @Override public int hashCode() { // 根据对象的属性生成哈希码 }
- getClass()方法:用于获取对象的运行时类对象.这对于运行时类型检查和反射操作非常有用.
Object obj = new Integer(10); Class<?> objClass = obj.getClass(); System.out.println("对象的类是:" + objClass.getName());
- clone()方法:用于创建对象的浅拷贝
@Override protected Object clone() throws CloneNotSupportedException { // 执行适当的拷贝操作来创建一个新对象 }
- finalize()方法:Object类中包含了finalize()方法,用于垃圾回收时的对象清理操作。通常,不建议在自定义类中覆盖这个方法,而是使用Java的垃圾回收机制来处理对象的销毁。
- wait()、notify()和notifyAll()方法:Object类中包含了用于多线程编程的等待和通知机制的方法。这些方法允许线程等待某个条件的满足或者通知其他线程条件已经满足.
synchronized (lockObject) { lockObject.wait(); // 线程等待条件的满足 // ... lockObject.notify(); // 通知其他线程条件已经满足 }
- 总结:Object类在Java中具有特殊的地位,它是所有类的父类,提供了一些基本的方法和特性,可用于所有Java对象。自定义类通常需要覆盖equals()、hashCode()、toString()等方法,以便更好地满足具体需求。同时,Object类也提供了一些多线程编程和反射操作的基础支持。
- 父类
泛型
- Java泛型是一种强类型,允许您编写具有参数化类型的类、接口和方法,以增加代码的可重用性、类型安全性和性能。泛型使您能够编写通用的代码,以适应各种数据类型,而不需要在编译时强制进行类型转换.
- 基本概念和用法
- 泛型类:使用泛型类可以创建具有参数化类型的类.例如:下面的泛型类可以存储任何类型的对象.
public class Box<T> { private T value; public Box(T value) { this.value = value; } public T getValue() { return value; } }
- 使用泛型类时,可以指定实际的类型参数
Box<Integer> intBox = new Box<>(42); Box<String> stringBox = new Box<>("Hello, Java!");
- 泛型方法:泛型方法是在方法声明中使用泛型类型参数的方法,如下,泛型方法可以根据传入的参数类型自动推断类型参数,或者明确指定类型参数.
public <T> T doSomething(T value) { // 执行操作 return value; }
- 泛型接口:与泛型类类似,可以创建泛型接口,以在接口中使用参数化类型
public interface List<T> { void add(T item); T get(int index); }
- 通配符:用于表示未知类型或限制泛型类型的上界或下界。通配符有三种形式
- 通配符的三种形式
?
表示未知类型? extends T
表示类型的上界,表示类型必须是T或T的子类? super T
表示类型的下界,表示类型必须是T或者T的父类
- 通配符通常用于方法参数、方法返回值和集合中
- 通配符的三种形式
- 类型擦除
- Java的泛型在编译时会执行类型擦除,这意味着在运行时,泛型类型信息会被擦除,以保持与旧版本Java的兼容性。这导致了一些限制,例如无法在运行时检查泛型类型
- 泛型约束
- 泛型可以使用类型约束来限制类型参数的范围。例如,可以使用extends来指定类型参数必须是某个类的子类
public <T extends Number> void processNumber(T number) { // 处理数字 }
- 总结
- 泛型是Java中强大且常用的特性之一,它可以提高代码的类型安全性和可维护性,同时减少了类型转换的需要。它使得编写通用的数据结构和算法更加容易,因为这些代码可以适用于各种不同类型的数据。
序列化
- 序列化是一种将对象转换为字节流的过程,以便将对象保存到文件、数据库或通过网络进行传输。序列化的过程允许对象的状态被保存,以便稍后可以恢复为原始对象。反序列化则是将字节流转换回对象的过程,恢复对象的状态.
- 基本用法和示例
- 实现Seriazlizable接口
- 需要一个类可序列化,需要实现
java.io.Serializable
接口.这个接口是一个标记接口,不包含任何方法.
import java.io.Serializable; public class MyClass implements Serializable { // 类的成员和方法 }
- 序列化对象
- 使用
ObjectOutputStream
类可以将对象序列化为字节流,并将其写入输出流.
try (FileOutputStream fileOut = new FileOutputStream("object.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut)) { MyClass myObject = new MyClass(); out.writeObject(myObject); } catch (IOException e) { e.printStackTrace(); }
- 反序列化对象
- 使用
ObjectInputStream
类可以从输入流中读取字节流,并将其反序列化为对象.
try (FileInputStream fileIn = new FileInputStream("object.ser"); ObjectInputStream in = new ObjectInputStream(fileIn)) { MyClass myObject = (MyClass) in.readObject(); // 使用反序列化后的对象 } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }
- 版本控制
- 在进行序列化时,为了确保反序列化的兼容性,建议在类中添加一个 serialVersionUID 字段,用于指定序列化版本号。这样,如果类的结构发生变化,可以通过修改版本号来处理不同版本的序列化数据.
private static final long serialVersionUID = 1L;
- 总结
- 需要注意的是,不是所有的对象都可以序列化,例如,线程、文件句柄等系统资源不能被序列化。另外,序列化和反序列化过程可能涉及到安全性和性能方面的考虑,因此需要谨慎使用。
- 总之,Java 序列化是一种重要的机制,用于将对象转换为字节流,以便进行数据存储和传输。通过实现 Serializable 接口,可以轻松地实现对象的序列化和反序列化。但要注意,序列化和反序列化可能会引入一些复杂性和潜在的问题,因此需要仔细考虑和测试。
网络编程
- Java网络编程是使用 Java 编程语言创建网络应用程序的过程。它允许您通过网络连接发送和接收数据,创建客户端-服务器应用程序,以及构建各种网络通信工具。Java 提供了广泛的网络编程库和API,使网络编程变得相对容易
- Socket 编程
- Socket 是网络编程的基础,用于在计算机之间建立通信连接。Java 提供了 java.net 包,其中包含了 Socket 和 ServerSocket 类,用于创建套接字连接。
- 客户端套接字:客户端使用 Socket 类来连接到服务器,并发送和接收数据。
- 服务器套接字:服务器使用 ServerSocket 类来监听客户端连接请求,并创建新的套接字来处理客户端通信。
- Socket 是网络编程的基础,用于在计算机之间建立通信连接。Java 提供了 java.net 包,其中包含了 Socket 和 ServerSocket 类,用于创建套接字连接。
- URL和HttpURLConnection
- Java提供了 java.net.URL 类,用于处理统一资源定位符(URL)。通过 URL 类,可以创建连接到远程资源(如网页或文件)的对象,并读取数据。HttpURLConnection 类扩展了 URLConnection 类,用于进行HTTP通信,例如发送HTTP请求并接收HTTP响应。
- TCP和UDP协议
- Java支持传输控制协议(TCP)和用户数据报协议(UDP)。TCP 提供可靠的连接,适用于需要数据完整性的场景,如HTTP。UDP 提供无连接的通信,适用于实时性要求较高的应用,如音频和视频流。
- 多线程编程
- 网络编程通常涉及多个并发连接。Java 的多线程机制非常有用,可以在不同线程中处理多个客户端连接。这有助于实现高并发性能。
- 网络安全性
- 网络编程需要考虑网络安全性问题。Java 提供了安全套接字层(SSL)支持,可以使用 javax.net.ssl 包来实现加密和身份验证。还可以使用 Java 安全管理器(Security Manager)来控制应用程序的安全性。
- NIO(New I/O)
- Java的NIO包括了java.nio和java.nio.channels 包,提供了非阻塞的、高性能的I/O操作。NIO 是一种事件驱动的编程方式,适用于需要处理大量并发连接的网络应用。
- RMI(远程方法调用)
- Java RMI允许在不同的Java虚拟机之间进行远程方法调用。这对于构建分布式系统非常有用,允许客户端调用远程服务器上的方法,就像调用本地方法一样。
- Web服务和RESTfulAPI
- Java可以用于创建和消费 Web 服务,包括SOAP和RESTful风格的服务。javax.xml.ws 和 javax.ws.rs 包提供了相关的API
- 网络库和框架
- 除了Java标准库外,还有许多第三方网络库和框架,如Apache HttpClient、Netty、Spring Framework等,可以简化网络编程任务,提供更高级的功能和性能优化
- 总结:Java网络编程是一个广泛的领域,可以用于各种不同的应用,包括Web应用、游戏、实时通信和分布式系统。了解这些基本概念和工具可以帮助您开始进行Java网络编程,并构建强大的网络应用程序。
发送邮件
- 使用Java发送邮件可以使用JavaMail API,这是一个用于处理邮件的强大的库.
- 基本用法和示例
-
导入必要的库
- 首先,您需要导入JavaMail API和Java Activation Framework (JAF)的库。您可以从Oracle的网站或Maven中央仓库下载这些库的JAR文件并添加到您的项目中.
-
编写发送邮件的代码
import java.util.Properties; import javax.mail.*; import javax.mail.internet.*; public class SendEmail { public static void main(String[] args) { // 收件人邮箱地址 String to = "[email protected]"; // 发件人邮箱地址 String from = "[email protected]"; // 邮件服务器主机名 String host = "smtp.example.com"; // 获取系统属性 Properties properties = System.getProperties(); // 设置邮件服务器 properties.setProperty("mail.smtp.host", host); // 获取默认的Session对象 Session session = Session.getDefaultInstance(properties); try { // 创建一个默认的MimeMessage对象 MimeMessage message = new MimeMessage(session); // 设置发件人 message.setFrom(new InternetAddress(from)); // 设置收件人 message.addRecipient(Message.RecipientType.TO, new InternetAddress(to)); // 设置邮件主题 message.setSubject("这是邮件主题"); // 设置邮件内容 message.setText("这是邮件内容"); // 发送邮件 Transport.send(message); System.out.println("邮件发送成功"); } catch (MessagingException mex) { mex.printStackTrace(); } } }
- 在这个示例中,你需要替换以下部分的占位符
- to:收件人的邮箱地址
- from:发件人的邮箱地址
- host:邮件服务器的主机名
- 在这个示例中,你需要替换以下部分的占位符
-
配置发件人的邮箱
- 您可能需要提供发件人的邮箱地址和密码,以便通过SMTP服务器进行身份验证
// 设置发件人邮箱账号和密码 String username = "[email protected]"; String password = "your_email_password"; // 创建Authenticator对象,用于进行身份验证 Authenticator authenticator = new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } }; // 获取带有身份验证的Session对象 Session session = Session.getInstance(properties, authenticator);
- 配置邮件服务器端口和协议
- 默认情况下,JavaMail使用SMTP协议的25号端口来发送邮件。如果需要使用其他端口或协议(例如SSL或TLS),则需要进一步配置properties中的属性,以及选择合适的端口和协议。这将取决于您的邮件提供商和邮件服务器的要求
-
- 注意事项
- 发送邮件可能涉及到网络配置、防火墙规则和邮件服务器的限制,因此请确保您的网络环境和邮件服务器允许发送邮件。
- 在实际应用中,建议将邮件服务器的配置参数(如主机名、端口、用户名、密码)放在外部配置文件中,以增加安全性和可维护性。
- 请注意,使用JavaMail API发送邮件需要额外的库和配置,这些细节会因邮件服务器提供商而异。在实际应用中,您可能需要查阅邮件服务器提供商的文档以获取更详细的设置和配置信息
- 总结
- 演示了如何使用JavaMail API来发送邮件。在实际应用中,您可能需要更复杂的邮件格式、附件、多个收件人等功能,JavaMail API提供了广泛的功能来满足这些需求.
多线程编程
-
Java多线程编程是指在Java程序中同时执行多个线程的编程技术.多线程允许程序并行执行多个任务,提高了程序的性能和响应性.Java提供了多线程编程的支持,包括内置的线程类和丰富的多线程API.
-
主要概念和关键元素
- 线程和线程对象
- 线程是程序的基本执行单元,Java中的线程由Thread类表示.要创建一个线程,可以扩展Thread类并覆盖其run()方法,然后通过创建实例并调用start()方法来启动线程.
class MyThread extends Thread { public void run() { // 线程的执行代码 } } public class Main { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // 启动线程 } }
- 实现Runnable接口
- 除了扩展 Thread 类,还可以实现 Runnable 接口,将线程的任务定义在 run() 方法中,并使用 Thread 类的构造函数来创建线程对象
class MyRunnable implements Runnable { public void run() { // 线程的执行代码 } } public class Main { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); // 启动线程 } }
- 线程生命周期
- 线程有不同的状态,包括新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和终止(Terminated)等。线程的状态会随着时间的推移而变化,取决于线程的活动和资源的可用性.
- 线程同步
- 多线程程序可能会涉及共享资源的并发访问,这可能导致数据竞争和不确定性的结果。为了确保线程安全,可以使用 synchronized 关键字来控制对共享资源的访问.
public synchronized void synchronizedMethod() { // 同步的代码块 }
- 线程池
- 线程池是一种管理和重用线程的机制,可以有效地控制并发线程的数量。Java 提供了 Executor 和 ExecutorService 接口以及 ThreadPoolExecutor 类,用于创建和管理线程池
- 线程通信
- 多个线程之间可能需要相互通信和协调工作。Java 提供了 wait()、notify()、notifyAll() 等方法,用于线程之间的等待和通知.
- 守护线程
- 守护线程是一种在后台运行的线程,当所有非守护线程结束时,它们会自动结束。可以使用 setDaemon(true) 方法将线程设置为守护线程.
Thread daemonThread = new Thread(() -> { // 线程的执行代码 }); daemonThread.setDaemon(true); daemonThread.start();
- 线程异常处理
- 线程内部的异常通常无法传递到外部,因此需要在线程内部捕获和处理异常,并通常需要使用 try-catch 块来处理异常.
Thread thread = new Thread(() -> { try { // 线程的执行代码 } catch (Exception e) { e.printStackTrace(); } }); thread.start();
- 线程和线程对象
-
总结
- 以上是 Java 多线程编程的基本概念和关键元素。多线程编程可以用于处理并发任务,提高程序性能,但也需要小心处理线程同步和异常处理等问题,以避免潜在的错误和不稳定性。 Java 提供了丰富的多线程 API,可以满足各种多线程编程需求.
Applet 基础
- 前后端分离技术的流程,包括前端的Vue和React框架用的较多,此处不做介绍.