设计模式是前辈们经过实践验证总结的解决方案,帮助我们构建出更具可维护性、可扩展性和可读性的代码。当然,在面试的过程中,也会或多或少的被问到。那么今天,我们就来看一道设计模式中的常见面试问题:JDK 中都用了哪些设计模式?

我按照大家比较熟悉且好理解的方式,把 JDK 中使用的设计模式总结了一下,如下图所示:



那么,接下来我们一个个来看。

1.单例模式

单例模式保证一个类只有一个实例,并提供一个全局访问点。

Runtime 类使用了单例模式,如下源码可知:

public class Runtime {
private static final Runtime currentRuntime = new Runtime();
private static Version version;
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class {@code Runtime} are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the {@code Runtime} object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
// 省略其他源码
}

从以上源码可以看出,Runtime 使用的饿汉方式实现了单例模式。

2.工厂模式

工厂模式提供了一种将对象创建的过程封装在一个单独的类中的方法,这个类就是工厂类。

线程池中的所有线程的创建都是通过工厂创建的,使用的就是工厂模式,具体源码如下:

3.代理模式

代理模式是一种为其他对象提供一种代理以控制对这个对象的访问的设计模式。代理对象在客户端和目标对象之间起到中介的作用,并且可以去掉客户不能看到的内容和服务或者添加客户需要的额外服务。

JDK 内置了动态代理的功能,动态代理是代理模式的一种实现,它是由 java.lang.reflect.Proxy 类提供的。

Proxy 使用 Demo 如下:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; // 1.接口
interface Subject {
void doSomething();
} // 2.目标类(被代理类)
class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject is doing something");
}
} // 3.动态代理类
class DynamicProxyHandler implements InvocationHandler {
private Object target;
DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before calling method");
Object result = method.invoke(target, args);
System.out.println("After calling method");
return result;
}
} public class JDKProxyDemo {
public static void main(String[] args) {
// 创建真实对象
Subject realSubject = new RealSubject();
// 创建动态代理处理器
InvocationHandler handler = new DynamicProxyHandler(realSubject);
// 创建代理对象
Subject proxySubject = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
handler);
// 调用代理对象的方法
proxySubject.doSomething();
}
}

4.迭代器模式

迭代器模式能够提供一种简单的方法来遍历容器中的每个元素。通过迭代器,用户可以轻松地访问容器中所有的元素,简化了编程过程。

Iterable 就是标准的迭代器模式,Collection 就是 Iterator 的子类,它的使用代码如下:

import java.util.ArrayList;
import java.util.Iterator; public class IteratorDemo {
public static void main(String[] args) {
// 创建一个 ArrayList 并添加元素
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange"); // 获取迭代器
Iterator<String> iterator = list.iterator(); // 使用迭代器遍历集合
while (iterator.hasNext()) {
String fruit = iterator.next();
System.out.println("Fruit: " + fruit);
}
}
}

5.模版方法模式

模板方法模式(Template Method Pattern)定义了一个操作中的算法骨架,将一些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

在 AQS(AbstractQueuedSynchronizer) 中,acquire 方法和 release 方法使用了模板方法模式。

这些方法之所以被认为是模板方法模式,是因为它们定义了一个操作的基本框架或流程,但其中的某些关键步骤被设计为抽象方法,留给子类去具体实现。

以 acquire 方法为例,它大致的流程包括尝试获取资源、如果获取失败则将当前线程加入等待队列、阻塞线程等步骤。但是具体如何判断能否获取资源(通过调用 tryAcquire 方法),以及在获取失败后的一些处理细节,是由子类去实现的,具体源码如下:

protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}

例如,基于 AQS 实现的 ReentrantLock 中就重写了 tryAcquire 方法,实现源码如下:

6.装饰器模式

装饰器模式是在不修改原对象的基础上,动态地给对象添加额外功能的设计模式。

BufferedInputStream 就是典型装饰器模式,当使用普通的 InputStream 读取数据时,每次可能都会进行实际的 I/O 操作,而 BufferedInputStream 会先将一部分数据读入缓冲区,后续的读取操作可以直接从缓冲区获取,减少了实际的 I/O 次数。

例如以下代码:

InputStream inputStream = new FileInputStream("file.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);

BufferedInputStream 并没有改变 FileInputStream 的基本结构和接口,只是为其添加了缓冲的特性

7.策略模式

策略模式定义了一系列可互换的算法,并将每一个算法封装起来,使它们可以互相替换。

Comparator 是策略模式的一个典型例子,Comparator 接口定义了一个比较两个对象的方法 compare(T o1, T o2)。这个接口允许用户定义不同的比较策略,使得我们可以灵活地改变排序或比较逻辑。

例如以下示例代码:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator; public class StrategyPatternExample {
static class Person {
private String name;
private int age;
// 忽略 Setter、Getter 等方法
}
// 按照年龄升序排列
static class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return Integer.compare(p1.getAge(), p2.getAge());
}
}
// 按照姓名降序排列
static class NameDescendingComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p2.getName().compareTo(p1.getName());
}
}
public static void main(String[] args) {
ArrayList<Person> people = new ArrayList<>();
people.add(new Person("Alice", 30));
people.add(new Person("Bob", 25));
people.add(new Person("Charlie", 35)); // 使用年龄升序的策略
Collections.sort(people, new AgeComparator()); // 使用姓名降序的策略
Collections.sort(people, new NameDescendingComparator());
}
}

8.建造者模式

建造者模式是一种创建型设计模式,用于通过一系列的步骤来创建复杂的对象。它将对象的构建过程与其表示相分离,使得同样的构建过程可以创建不同的表示。

在 JDK 中,使用建造者模式的常见例子是 StringBuilder 和 StringBuffer 类。

虽然这两个类本身不是传统意义上的建造者模式实现(因为建造者模式通常用于构建不同的表示或者不同部分的同一个对象),它们提供了一种链式调用的方式来构建和修改字符串,这在某种程度上体现了建造者模式的思想。

例如以下代码:

public class StringBuilderDemo {
public static void main(String[] args) {
// 使用 StringBuilder 构建和修改字符串
StringBuilder builder = new StringBuilder();
builder.append("Hello")
.append(", ")
.append("world")
.append("!")
.insert(7, "beautiful ")
.deleteCharAt(13); // 输出构建和修改后的字符串
System.out.println(builder.toString());
// 输出: Hello, beautiful world!
}
}

StringBuilder 通过链式调用 append、insert 和 deleteCharAt 方法来逐步构建和修改字符串。这种方式使得构建和修改字符串的过程更加流畅和易于阅读。

课后思考

Spring 中都用了哪些设计模式?

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

面试官:JDK中都用了哪些设计模式?的更多相关文章

  1. 面试官:“谈谈Spring中都用到了那些设计模式?”。

    我自己总结的Java学习的系统知识点以及面试问题,已经开源,目前已经 41k+ Star.会一直完善下去,欢迎建议和指导,同时也欢迎Star: https://github.com/Snailclim ...

  2. 面试官:服务器安装 JDK 还是 JRE?可以只安装 JRE 吗?

    前些日子有知友面试时被问到如题所示的问题,由于他之前没有准备到这些最最基础的知识,没有考虑过这个问题,所以被问到时竟一脸萌币,回答的不是很好.这道题主要考的是对 Java 基础知识的了解,有些同学可能 ...

  3. 面试官的七种武器:Java篇

    起源 自己经历过的面试也不少了,互联网的.外企的,都有.总结一下这些面试的经验,发现面试官问的问题其实不外乎几个大类,玩不出太多新鲜玩意的.细细想来,面试官拥有以下七种武器.恰似古龙先生笔下的武侠世界 ...

  4. Android开发面试经——6.常见面试官提问Android题②(更新中...)

    版权声明:本文为寻梦-finddreams原创文章,请关注:http://blog.csdn.net/finddreams 关注finddreams博客:http://blog.csdn.net/fi ...

  5. 以技术面试官的经验分享毕业生和初级程序员通过面试的技巧(Java后端方向)

    本来想分享毕业生和初级程序员如何进大公司的经验,但后来一想,人各有志,有程序员或许想进成长型或创业型公司或其它类型的公司,所以就干脆来分享些提升技能和通过面试的技巧,技巧我讲,公司你选,两厢便利. 毕 ...

  6. (转)史上最全 40 道 Dubbo 面试题及答案,看完碾压面试官!

    背景:因为自己的简历写了dubbo,面试时候经常被问到.实际自己对dubbo的认识只停留在使用阶段,所以有必要好好补充下基础的理论知识. https://zhuanlan.zhihu.com/p/45 ...

  7. 史上最全 40 道 Dubbo 面试题及答案,看完碾压面试官

    想往高处走,怎么能不懂 Dubbo? Dubbo是国内最出名的分布式服务框架,也是 Java 程序员必备的必会的框架之一.Dubbo 更是中高级面试过程中经常会问的技术,无论你是否用过,你都必须熟悉. ...

  8. 从面试官甄别项目经验的角度,说说如何在简历中写项目经验(java后端方向)

    在大多的JD(职位介绍)里,会写明该职位需要xx时间的相关经验,换句话说就是需要在简历中看到一定年限的相关商业项目经验,否则估计连面试的机会都没. 在本文里,不讨论这种门槛是否合理,而会以Java相关 ...

  9. 8年经验面试官详解 Java 面试秘诀

      作者 | 胡书敏 责编 | 刘静 出品 | CSDN(ID:CSDNnews) 本人目前在一家知名外企担任架构师,而且最近八年来,在多家外企和互联网公司担任Java技术面试官,前后累计面试了有两三 ...

  10. 【Spring注解驱动开发】面试官:如何将Service注入到Servlet中?朋友又栽了!!

    写在前面 最近,一位读者出去面试前准备了很久,信心满满的去面试.没想到面试官的一个问题把他难住了.面试官的问题是这样的:如何使用Spring将Service注入到Servlet中呢?这位读者平时也是很 ...

随机推荐

  1. Win10下载纯净版ISO镜像

    进入windows官网下载页面 1.F12 进入开发者模式->选择浏览模式为手机->机型设置为Ipad Air ->刷新页面->下载选项出现 下图第二步选择完成后,需要刷新一下 ...

  2. PackageScanner

    package com.cmb.cox.utils;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;im ...

  3. 面试官:告诉我为什么static和transient关键字修饰的变量不能被序列化?

    一.写在开头 在上一篇学习序列化的文章中我们提出了这样的一个问题: "如果在我的对象中,有些变量并不想被序列化应该怎么办呢?" 当时给的回答是:不想被序列化的变量我们可以使用tra ...

  4. 推荐一款基于业务行为驱动开发(BDD)测试框架:Cucumber!

    大家好,我是狂师. 今天给大家介绍一款行为驱动开发测试框架:Cucumber. 1.介绍 Cucumber是一个行为驱动开发(BDD)工具,它结合了文本描述和自动化测试脚本.它使用一种名为Gherki ...

  5. NXP i.MX 8M Plus工业开发板规格书(四核ARM Cortex-A53 + 单核ARM Cortex-M7,主频1.6GHz)

      1 评估板简介 创龙科技TLIMX8MP-EVM是一款基于NXP i.MX 8M Plus的四核ARM Cortex-A53 + 单核ARM Cortex-M7异构多核处理器设计的高性能工业评估板 ...

  6. Spring注解之参数校验@Validated和@Valid

    @Validated和@Valid的区别 Spring Validation验证框架对参数的验证机制提供了@Validated(Spring's JSR-303 规范,是标准 JSR-303 的一个变 ...

  7. jQuery -- 手稿

  8. C#皮肤美化

    关于Winform窗体美化,目前大致了解是有两种方式:第一种方式是重写Winform本身的控件,不过这需要非常熟悉控件的各个属性和事件并且要求具有很高的GDI绘图技术.第二种方式是借助第三方Winfo ...

  9. 全网最适合入门的面向对象编程教程:14 类和对象的 Python 实现-类的静态方法和类方法,你分得清吗?

    全网最适合入门的面向对象编程教程:14 类和对象的 Python 实现-类的静态方法和类方法,你分得清吗? 摘要: 本文主要介绍了Python中类和对象中的类方法和静态方法,以及类方法和静态方法的定义 ...

  10. ComfyUI进阶:Comfyroll插件 (一)

    ComfyUI进阶:Comfyroll插件 (一) 前言: 学习ComfyUI是一场持久战,而Comfyroll Studio 是一款功能强大的自定义节点集合,专为 ComfyUI 用户打造,旨在提供 ...