上一篇地址:持续总结中!2024年面试必问 100 道 Java基础面试题(四十九)-CSDN博客
九十九、请解释Java中的单例模式及其实现方式
单例模式(Singleton Pattern)是一种常用的软件设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。单例模式在Java中的实现有多种方式,每种方式都有其特点和适用场景。
单例模式的特点:
- 单例类只能有一个实例:单例模式的核心是通过某种机制确保一个类只有一个实例被创建。
- 全局访问点:单例类提供了一个全局访问点,允许外部代码获取并使用这个唯一的实例。
- 线程安全:在多线程环境中,单例模式需要确保只有一个线程能够创建实例。
单例模式的实现方式:
懒汉式(线程不安全): 实现简单,但是线程不安全。只有当第一次调用
getInstance()
方法时,才会创建实例。public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
懒汉式(线程安全): 通过在
getInstance()
方法上加锁来保证线程安全。public class Singleton { private static Singleton instance; private Singleton() {} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
饿汉式: 在类加载时就创建实例,简单且线程安全,但是可能导致资源浪费,因为不管需不需要,类加载时就完成实例化。
public class Singleton { private static final Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } }
双重检查锁定(Double-Checked Locking,DCL): 在第一次调用
getInstance()
方法时,先检查实例是否存在,如果不存在,则通过加锁来创建实例。这种方式既延迟了实例化,又避免了同步带来的性能影响。public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
静态内部类: 利用Java的类加载机制来实现线程安全的单例模式。
public class Singleton { private Singleton() {} public static Singleton getInstance() { return SingletonHolder.INSTANCE; } static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } }
枚举单例: 使用Java枚举来实现单例,这是最简单的单例实现方式,也是线程安全的。
public enum Singleton { INSTANCE; public void someMethod() { // 方法实现 } }
注意事项:
- 序列化:如果单例类实现了
Serializable
接口,需要提供readResolve()
方法来保证反序列化时不会创建新的实例。 - 反射:通过反射可以破坏单例的实例限制,因此在设计时需要考虑这一点。
- 延迟加载:单例类通常使用延迟加载,即在第一次使用时才创建实例。
单例模式在实际应用中非常广泛,如配置管理器、连接池、线程池等。然而,单例模式也存在一些争议,如它可能使得单元测试变得困难,有时也会导致代码难以理解。因此,在决定使用单例模式时,需要权衡其优缺点。
一百、在Java中,如何使用正则表达式进行字符串匹配和处理?
在Java中,正则表达式(Regular Expression)用于描述字符串的模式,它可以用来检查一个字符串是否符合我们定义的模式、查找符合某个模式的字符串、替换或者分割字符串等。Java通过java.util.regex
包提供了对正则表达式的全面支持。
正则表达式的基本概念:
- 字符:正则表达式由普通字符(如字母、数字等)和特殊字符(如
.
、*
、+
等)组成。 - 元字符:特殊字符在正则表达式中具有特殊含义,如
.
表示任意单个字符,*
表示前面的字符可以出现零次或多次。
Java中使用正则表达式的主要类:
- Pattern:表示正则表达式的编译表示形式,是正则表达式编译后的结果。
- Matcher:用于将
Pattern
与输入字符串进行匹配的一个引擎,可以进行区域匹配。
字符串匹配和处理的基本步骤:
- 编译正则表达式:创建
Pattern
对象。
Pattern pattern = Pattern.compile("正则表达式字符串");
- 创建匹配器:使用
Pattern
对象的matcher()
方法创建Matcher
对象。
Matcher matcher = pattern.matcher("要匹配的字符串");
- 进行匹配:使用
Matcher
对象的find()
方法进行查找,或者matches()
方法进行整体匹配。
boolean found = matcher.find(); // 查找下一个匹配
boolean matches = matcher.matches(); // 整体匹配
- 替换文本:使用
Matcher
对象的replaceFirst()
或replaceAll()
方法进行替换。
String replaced = matcher.replaceFirst("替换文本"); // 替换首次匹配的文本
String replacedAll = matcher.replaceAll("替换文本"); // 替换所有匹配的文本
- 分割文本:使用
Pattern
对象的split()
方法进行分割。
String[] parts = pattern.split("要分割的字符串");
示例代码:
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexExample {
public static void main(String[] args) {
// 编译正则表达式
Pattern pattern = Pattern.compile("\\d+"); // 匹配一个或多个数字
// 创建匹配器并匹配字符串
String text = "There are 123 apples and 456 oranges";
Matcher matcher = pattern.matcher(text);
// 查找并输出所有匹配的数字
while (matcher.find()) {
System.out.println(matcher.group()); // 输出匹配的子串
}
// 替换所有匹配的数字为"XXX"
String replacedText = matcher.replaceAll("XXX");
System.out.println(replacedText);
// 使用正则表达式分割字符串
String[] words = pattern.split(text);
System.out.println(java.util.Arrays.toString(words));
}
}
注意事项:
- 性能:对于复杂的正则表达式或长字符串,性能可能是个问题。在可能的情况下,尽量使用简单的正则表达式。
- 异常:错误的正则表达式格式会抛出
PatternSyntaxException
。 - 模式匹配:正则表达式匹配是区分大小写的,如果需要进行不区分大小写的匹配,可以使用
Pattern.CASE_INSENSITIVE
标志。 - 分组:正则表达式中的括号
()
表示分组,可以用来捕获匹配的子串。
正则表达式是处理字符串的强大工具,通过Java的Pattern
和Matcher
类,我们可以方便地在程序中使用正则表达式进行复杂的字符串匹配和处理。