首页 > 其他分享 >面试官:JDK中都用了哪些设计模式?

面试官:JDK中都用了哪些设计模式?

时间:2024-08-15 15:55:33浏览次数:8  
标签:面试官 JDK 模式 class static new 设计模式 public

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

我按照大家比较熟悉且好理解的方式,把 JDK 中使用的设计模式总结了一下,如下图所示:
image.png
那么,接下来我们一个个来看。

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,模式,class,static,new,设计模式,public
From: https://www.cnblogs.com/vipstone/p/18361126

相关文章

  • 设计模式的7大基本原则
    设计模式是解决问题的经验总结,是软件开发中常用的一种设计思想和方法。在软件开发过程中,遵循设计模式可以提高代码的可重用性、可维护性和可扩展性。设计模式的基本原则是软件开发过程中的指导方针,它们是在解决问题时需要遵循的基本原则。本文将介绍设计模式的7大基本原则,......
  • 【ArrayList】JDK1.8源码详细注释 以及如何实现线程安全的链表
    ArrayList(JDK8)ArrayList有四个内部类,成员内部类Itr,成员内部类ListItr,静态内部类SubList,ArrayListSpliterator(暂时用不到)Itr是Iterator的实现类,支持正向遍历,ArrayList的iterator方法返回一个Itr对象ListItr是ListIterator的实现类,支持双向遍历,ArrayList的listIterator方法......
  • 设计模式-延迟加载(Lazy Load)
    概念一个对象,它虽然不包含所需要的所有数据,但是知道怎么获取这些数据。加载一个对象会引起大量相关对象的加载,这样会损害系统的性能。延迟加载会暂时终止这个加载过程。运行机制四种实现延迟加载的方法:延迟初始化(Lazyinitialization)。每次访问属性域都要先检查该域是否......
  • 华为云 CentOS 7.9安装jdk1.8教程
    1、通过yum安装:使用查找命令:yum-ylistjava*使用安装命令:yuminstall-yjava-1.8.0-openjdk.x86_64 (选择自己要安装的版本,名称必须与上面的名称一致)默认安装到:usr/lib/jvm然后查看版本:java-version 2、通过自己下载解压安装:可以选择自己要下载的具体版本,比较灵活,可......
  • 云计算课程设计(Prometheus+grafana+Flume+ganglia+mysql+jdk)
    一、准备环境prometheus下载地址:https://github.com/prometheus/prometheus/releases/download/v2.52.0-rc.1/prometheus-2.52.0-rc.1.windows-amd64.zipgrafana下载地址:https://dl.grafana.com/enterprise/release/grafana-enterprise-10.4.2.windows-amd64.zip......
  • 在虚拟机CentOS中安装jdk
    公众号本文地址:在虚拟机CentOS中安装jdk本文主要是记录在CentOS中安装新的JDK的过程。在虚拟机的centos中安装Jdk主要分为三步,第一步上传jdk文件到centos中,第二步解压jdk文件,第三步配置环境变量。一般在安装完CentOS后系统是有jdk的,但是默认为openjdk1.8.0版本由于开发需要使......
  • 设计模式-创建型模式1:单例模式+工厂模式
    单例模式单例模式是创建型设计模式核心思想:一个类只有一个实例,并提供一个全局访问点来访问这个实例单例设计模式的实现懒汉式:只有请求实例时才完成创建,需要使用了再创建;饿汉式:在类加载时,已经完成实例创建;适用场景资源共享;只有一个实例;懒加载:对象本身比较消耗资源,在......
  • 面试官:说说volatile应用和实现原理?
    volatile是并发编程中的重要关键字,它的名气甚至是可以与synchronized、ReentrantLock等齐名,也是属于并发编程五杰之一。需要注意的是volatile并不能保证原子性,因此使用volatile并没有办法保证线程安全。并发编程五杰:PS:“并发编程五杰”是我个人起的名字,大家也不用太......
  • 29. Hibernate 面试官必须出的面试题
    1.前言本节课先和大家聊聊面试过程中需要注意的事项,再和大家一起讲解Hibernate中常见的面试题。2.面试技巧面试官出的面试题一般会有3个特点:强调原理性: 通过面试者对问题原理性的讲解,可以了解面试者是否真正理解、掌握了相关知识。对于知识而言,用是一个层次,说出来......
  • 设计模式 - 装饰器模式
    ......