JavaTutorial04
免责声明:本人设计模式学得一坨,因此本文没有详细的设计模式教程,只有针对几个问题的解答。教程?等老子重新学完再说😋
设计模式
说到底设计模式就是软件编程中的最佳实践,是前人面对具体问题,不断试错不断积累,总结出来的解决方案,的是为了更好的组织代码,提高代码的扩展性,维护性和复用的能力,是一种思想和方法论,没有严格的固定模板,可以根据场景灵活调整,也可以组合使用
谈谈你知道的设计模式?
大致按照模式的应用目标分类,设计模式可以分为创建型模式、结构型模式和行为型模式。
- 创建型模式,是对对象创建过程的各种问题和解决方案的总结,包括各种工厂模式(Factory、Abstract Factory)、单例模式(Singleton)、构建器模式(Builder)、原型模式(ProtoType)。
- 结构型模式,是针对软件设计结构的总结,关注于类、对象继承、组合方式的实践经验。常见的结构型模式,包括桥接模式(Bridge)、适配器模式(Adapter)、装饰者模式(Decorator)、代理模式(Proxy)、组合模式(Composite)、外观模式(Facade)、享元模式(Flyweight)等。
- 行为型模式,是从类或对象之间交互、职责划分等角度总结的模式。比较常见的行为型模式有策略模式(Strategy)、解释器模式(Interpreter)、命令模式(Command)、观察者模式(Observer)、迭代器模式(Iterator)、模板方法模式(Template Method)、访问者模式(Visitor)。
手撕单例模式?双检锁单例模式?
什么是单例模式?
想象一下你在管理一个公司。在整个公司中,只能有一个总经理,不能同时存在两个总经理,这就类似于单例模式的概念。
单例模式的核心思想就是:确保一个类在整个应用程序中只能创建一个对象实例,并提供一个全局访问点。
举一个具体的例子:
1 | public class CompanyManager { |
使用示例:
1 | public class Main { |
这个例子的关键点:
- 构造方法是私有的,这样其他类就不能直接创建新的实例
- 提供一个静态方法来获取实例,确保只创建一个对象
- 使用静态变量来保存这个唯一的实例
单例模式的常见应用场景:
- 配置管理器:整个应用只需要一个配置管理器
- 数据库连接池:统一管理数据库连接资源
- 日志记录器:集中管理日志记录
不过需要注意,上面的示例是最简单的单例实现,在多线程环境下可能会有问题。在实际开发中,我们通常会使用双重检查锁定或者枚举来实现更安全的单例模式。
想象一下你们公司的会议室系统。在预订会议室时,为了避免同一个时间段被多个人预订,我们需要一个预订检查机制:
- 第一次检查:快速看一眼会议室是否空闲
- 如果看起来空闲,我们会锁定预订系统
- 第二次检查:再次确认会议室确实空闲
- 最后才进行预订
这就类似于双检锁的工作方式。下面用代码来说明:
1 | public class CompanyManager { |
使用示例:
1 | public class Main { |
双检锁的好处:
- 线程安全:确保在多线程环境下也只会创建一个实例
- 性能优化:只有在第一次创建实例时才需要加锁
- 延迟加载:只有在真正需要时才创建实例
Spring等框架中使用了哪些模式?
- 单例模式(Singleton Pattern)
- Spring中的Bean默认都是单例的
- Spring通过ConcurrentHashMap实现单例注册表的特殊单例模式
1
2
3
4
5
6
7
8
9
10// Spring中单例的实现
public class DefaultSingletonBeanRegistry {
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
}
}
}
- 工厂模式(Factory Pattern)
- BeanFactory用于创建和管理Bean实例
- 将Bean的创建过程封装,客户端只需要知道Bean的名字
1
2
3// Spring中的工厂模式示例
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean("userService", UserService.class);
- 代理模式(Proxy Pattern)
- Spring AOP中使用JDK动态代理和CGLIB代理
- 实现方法拦截和增强
1
2
3
4
5
6
7
8// AOP代理示例
public class LoggingAspect {
public void logBefore() {
System.out.println("Before method execution");
}
}
- 模板方法模式(Template Method Pattern)
- JdbcTemplate封装了数据库操作
- RestTemplate封装了REST请求操作
1
2
3
4
5
6
7
8
9
10
11
12// JdbcTemplate使用示例
public class UserDao {
private JdbcTemplate jdbcTemplate;
public User getUser(long id) {
return jdbcTemplate.queryForObject(
"SELECT * FROM users WHERE id = ?",
new Object[]{id},
(rs, rowNum) -> new User(rs.getLong("id"), rs.getString("name"))
);
}
}
- 观察者模式(Observer Pattern)
- Spring事件机制(ApplicationEvent和ApplicationListener)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 自定义事件
public class UserCreatedEvent extends ApplicationEvent {
public UserCreatedEvent(User user) {
super(user);
}
}
// 事件监听器
public class UserCreatedListener implements ApplicationListener<UserCreatedEvent> {
public void onApplicationEvent(UserCreatedEvent event) {
// 处理用户创建事件
}
}
- 适配器模式(Adapter Pattern)
- Spring MVC中的HandlerAdapter
- 将不同类型的处理器(handlers)适配到统一的接口
- 责任链模式(Chain of Responsibility Pattern)
- Spring Security的过滤器链
1
2
3
4
5
6
7
8
9
10
public class SecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(new JwtAuthenticationFilter())
.addFilter(new JwtAuthorizationFilter());
}
}
- 策略模式(Strategy Pattern)
- Spring在资源访问时使用Resource接口
- 不同的资源类型(ClassPathResource、FileSystemResource等)实现不同的访问策略
- 建造者模式(Builder Pattern)
- 用于构建复杂对象,如SpringSecurity中的配置
1
2
3
4
5
6
7
8
9// Security配置的Builder模式
http
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin()
.loginPage("/login")
.permitAll();
Java8新特性
lambda有什么好处?应用场景是什么?
传统使用场景:
定义接口及其定义方法-创造类实现接口-创造形参为接口的函数(面向接口编程)-创造类实例并调用接口中的方法。。。

Lambda的好处:
·简化代码:减少匿名内部类的冗余代码,简化创建类到创建类实例的所有步骤,直接调用方法
·支持函数式编程:使 Java 能更好地支持函数式编程范式
一个简单的例子:
1 | //注意:函数式接口只能有唯一一个定义方法,否则不能使用Lamda表达式 |
当然,实践中经常用在stream流的处理上,使得代码变得十分简洁。
1 | // 在集合操作中的应用 |
方法引用是什么?有什么好处?应用场景是什么?
方法引用是 Java 8 引入的特性,它是 Lambda 表达式的一种简化写法。使用操作符 “::” 将方法名和对象或类的名字分隔开来。
当 Lambda 表达式仅仅是调用一个已存在的方法时,优先使用方法引用
如果需要对参数进行转换或者有额外的处理逻辑,则使用 Lambda 表达式
使用场景:
1 | List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); |
Java 中的 stream 流知道吗,有哪些功能?应用场景是什么?
StreamAPI 是一种用于处理数据的抽象概念,而不是具体的数据类型。它代表的是一种操作方式和思维模式。这就像是一条传送带(Stream),数据从一端输入,经过各种处理(过滤、转换等),最后从另一端输出结果。传送带本身不存储任何东西,它只是定义了”如何处理”的过程。
概括讲,可以将Stream流操作分为3种类型:
- 创建Stream
- Stream中间处理
- 终止Steam

怎么获取流
有很多方法获取 Stream ,一般最常见的是从 Collection 对象中获取 Stream。由于集合对象都实现了 Collection 接口,所以通过接口里定义的 stream 方法获救获取到由集合元素构成的 Steam。下面是一个从 List 对象获取 Stream 的例子。
1 | List<String> items = new ArrayList<String>(); |
流处理

举例:
1 | List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 4, 5); |
流终结

举例:
1 | List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5); |
Optional是什么?应用场景是什么?
Optional(可选值)是一种设计模式和编程概念,用于处理可能为空的值。
主要应用场景:
空值处理:避免NPE(空指针异常)
1
2
3//ofNullable() 创建一个即可空又可非空的 Optional 对象
Optional<String> name = Optional.ofNullable(user.getName());
String displayName = name.orElse("Unknown");方法返回值:明确表达返回值可能不存在
1
2
3
4public Optional<User> findUserById(Long id) {
// 可能找不到用户
return Optional.ofNullable(userDao.get(id));
}参数校验:优雅处理可选参数
1
2
3public void processOrder(Order order, Optional<String> couponCode) {
couponCode.ifPresent(code -> applyDiscount(order, code));
}
不建议使用get方法,没有确认值是否存在的情况下可能会导致NoSuchElementException,而加入判断条件又违背了引入Optional的初衷。因此,Optional的最佳实践如下:
1 | // 示例一:值存在时执行println,否则不执行 |
当然,Optional最大的优点是能与函数式编程相结合:
1 | User user1 = new User("张三", new Address("北京", "朝阳区")); |
在实际应用场景中,大对象 json套json,如果看里面某个字段是不是空用这个链式map调用很直观,不然一堆if嵌套才是折磨。
1 | // Optional方式 |
有人说,Optional的出现是为了解决函数式编程中判空副作用的问题。举例来说,一个快递员给一户人家送快递,这户人家是一家三口和一条狗,狗不能签收,但是三口中任意都能签收。在optional中null就是那个狗,一家三口就是其余可能的值。利用Optional进行封装后,单子将狗子也包含到了这户人家中,且进行了处理,这样快递员层面面对的就是户而不是可能是人,可能是狗。
以下是直观的代码显示:
1 | public class DeliveryExample { |
·