Java面试——设计模式(三)

Java高级工程师面试题总结及参考答案 一、面试题基础总结 1、JVM结构原理、GC工作机制详解 答:具体参照:JVM结构、GC工作机制详解 ,说到GC,记住两点:1、GC是负责回收所有无任何引用对象的内存空间。 注意:垃圾回收回收的是无任何引用的对象占据的内存空间而不是对象本身,2、GC回收机制的两种算法,a、引用计数法 b、可达性分析算法(这里的可达性,大家可以看基础2 Java对象的什么周期),至于更详细的GC... 阅读详情

13、享元模式的概念及Java实现

享元模式(Flyweight Pattern)主要通过对象的复用来减少对象创建的次数和数量,以减少系统内存的使用和降低系统的负载。享元模式属于结构型模式,在系统需要一个对象时享元模式首先在系统中查找并尝试重用现有的对象,如果未找到匹配的对象,则创建新对象并将其缓存在系统中以便下次使用。

享元模式主要用于避免在有大量对象时频繁创建和销毁对象造成系统资源的浪费,把其中共同的部分抽象出来,如果有相同的业务请求,则直接返回内存中已有的对象,避免重新创建。

下面以内存的申请和使用为例介绍享元模式的使用方法,创建一个MemoryFactory作为内存管理的工厂,用户通过工厂获取内存,在系统内存池有可用内存时直接获取该内存,如果没有则创建一个内存对象放入内存池,等下次有相同的内存请求过来时直接将该内存分配给用户即可。具体的UML设计如图所示。在这里插入图片描述
具体实现如下。

(1)定义Memory:

public  class  Memory  {
  private int size; //内存大小,单位为MB
  private boolean isused; //内存是否在被使用
  private String id; //内存id
    public  Memory(int  size,  boolean  isused,  String  id)  {
      this.size  =  size;
      this.isused  =  isused;
      this.id  =  id;
    }
//getter setter方法省略
}

(2)定义MemoryFactory工厂:

public  class  MemoryFactory  {
    private  final  static  Log  logger  =  LogFactory.getLog(MemoryFactory.class);
    //内存对象列表
    private  static  List<Memory>  memoryList  =  new  ArrayList<Memory>();
    public  static  Memory  getMemory(int  size){
      Memory  memory  =  null;
      for  (int  i  =  0  ; i<memoryList.size()  ; i++)  {
          memory  =  memoryList.get(i);
          //如果存在和需求size一样大小并且未使用的内存块,则直接返回
          if(memory.getSize()==size  &&  memory.isIsused()  ==false){
              memory.setIsused(true);
              memoryList.set(i, memory);
              logger.info("get  memory  form  memoryList:"+
                    JSON.toJSONString(memory));
               break;
          }
        }
        //如果内存不存在,则从系统中申请新的内存返回,并将该内存加入内存对象列表中
        if(memory  ==  null  ){
          memory  =  new  Memory(32, false, UUID.randomUUID().toString());
          logger.info("create  a  new  memory  form  system  and  add  to
                    memoryList:"+  JSON.toJSONString(memory));
          memoryList.add(memory);
        }
        return  memory;
    }
    //释放内存
    public  static  void   releaseMemory(String  id){
        for  (int  i  =  0  ; i<memoryList.size()  ; i++)  {
          Memory   memory  =  memoryList.get(i);
          //如果存在和需求size一样大小并且未使用的内存块,则直接返回
          if(memory.getId().equals(id)){
              memory.setIsused(false);
              memoryList.set(i, memory);
              logger.info("release  memory:"+  id);
              break;
          }
        }
    }
}

以上代码定义了工厂类MemoryFactory,在该类中定义了memoryList用于存储从系统中申请到的内存,该类定义了getMemory,用于从memoryList列表中获取内存,如果在内存中有空闲的内存,则直接取出来返回,并将该内存的使用状态设置为已使用,如果没有,则创建内存并放入内存列表;还定义了releaseMemory来释放内存,具体做法是将内存的使用状态设置为false。

(3)使用享元模式:

public  static  void  main(String[]  args)  {
    //首次获取内存,将创建一个内存
  Memory  memory  =  MemoryFactory.getMemory(32);
  //在使用后释放内存
  MemoryFactory.releaseMemory(memory.getId());
  //重新获取内存
  MemoryFactory.getMemory(32);
}

在使用享元模式时,直接从工厂类MemoryFactory中获取需要的数据Memory,在使用完成后释放即可,具体的运行结果如下:

[INFO]  MemoryFactory  -  create  a  new  memory  form  system  and  add  to
memoryList:{"id":"c5cc6dca-cf26-41ec-8552-
2f744721a24b", "isused":false, "size":32}
[INFO]  MemoryFactory  -  release  memory:c5cc6dca-cf26-41ec-8552-2f744721a24b
[INFO]  MemoryFactory  -  get  memory  form  memoryList:{"id":"c5cc6dca-cf26-41ec-8552-2f744721a24b", "isused":true, "size":32}

14、策略模式的概念及Java实现

策略模式(Strategy Pattern)为同一个行为定义了不同的策略,并为每种策略都实现了不同的方法。在用户使用的时候,系统根据不同的策略自动切换不同的方法来实现策略的改变。同一个策略下的不同方法是对同一功能的不同实现,因此在使用时可以相互替换而不影响用户的使用。

策略模式的实现是在接口中定义不同的策略,在实现类中完成了对不同策略下具体行为的实现,并将用户的策略状态存储在上下文(Context)中来完成策略的存储和状态的改变。

我们在现实生活中常常碰到实现目标有多种可选策略的情况,比如下班后可以通过开车、坐公交、坐地铁、骑自行回家,在旅行时可以选择火车、飞机、汽车等交通工具,在淘宝上购买指定商品时可以选择直接减免部分钱、送赠品、送积分等方式。

对于上述情况,使用多重if …else条件转移语句也可实现,但属于硬编码方式,这样做不但会使代码复杂、难懂,而且在增加、删除、更换算法时都需要修改源代码,不易维护,违背了开闭原则。通过策略模式就能优雅地解决这些问题。

下面以旅游交通工具的选择为例实现策略模式,具体的UML设计如图所示。

在这里插入图片描述
具体实现如下。

(1)定义TravelStrategy:

public  interface  TravelStrategy  {
void  travelMode();
}

以上代码定义了策略模式接口TravelStrategy,并在该接口中定义了方法travelMode()来表示出行方式。

(2)定义TravelStrategy的两种实现方式TravelByAirStrategy和TravelByCarStrategy:

public  class  TravelByAirStrategy  implements   TravelStrategy{
    private  final  static  Log  logger  =
LogFactory.getLog(TravelByAirStrategy.class);
    @Override
    public  void  travelMode()  {
      logger.info("travel  by  air");
    }
}
public  class  TravelByCarStrategy  implements   TravelStrategy{
    private  final  static  Log  logger  =
LogFactory.getLog(TravelByCarStrategy.class);
    @Override
    public  void  travelMode()  {
        logger.info("travel  by  car");
    }
}

以上代码定义了TravelStrategy的两个实现类TravelByAirStrategy和TravelByCarStrategy,分别表示基于飞机的出行方式和基于开车自驾的出行方式,并实现了方法travelMode()。

(3)定义Context实现策略模式:

public  class  Context  {
    private  TravelStrategy  travelStrategy;
    public  TravelStrategy  getTravelStrategy()  {
      return  travelStrategy;
    }
    public  void  setTravelStrategy(TravelStrategy  travelStrategy)  {
      this.travelStrategy  =  travelStrategy;
    }
    public  void  travelMode()  {
      this.travelStrategy.travelMode();
    }
}

以上代码定义了策略模式实现的核心类Context,在该类中持有TravelStrategy实例并通过setTravelStrategy()实现了不同策略的切换。

(4)使用策略模式:

public  static  void  main(String[]  args)  {
    Context  context  =  new  Context();
    TravelStrategy  travelByAirStrategy  =  new  TravelByAirStrategy();
    //设置出行策略为飞机
    context.setTravelStrategy(travelByAirStrategy);
    context.travelMode();
    logger.info("change  TravelStrategy  to  travelByCarStrategy......");
    //设置出行策略为开车自驾
    TravelStrategy  travelByCarStrategy=  new  TravelByCarStrategy();
    context.setTravelStrategy(travelByCarStrategy);
    context.travelMode();
}

在使用策略模式时,首先需要定义一个Context,然后定义不同的策略实现并将其注入Context中实现不同策略的切换。具体的执行结果如下:

[INFO]  TravelByAirStrategy  -  travel  by  air
[INFO]  StrategyDemo  -  change  TravelStrategy  to  travelByCarStrategy......
[INFO]  TravelByCarStrategy  -  travel  by  car

15、模板方法模式的概念及Java实现

模板方法(Template Method)模式定义了一个算法框架,并通过继承的方式将算法的实现延迟到子类中,使得子类可以在不改变算法框架及其流程的前提下重新定义该算法在某些特定环节的实现,是一种类行为型模式。

该模式在抽象类中定义了算法的结构并实现了公共部分算法,在子类中实现可变的部分并根据不同的业务需求实现不同的扩展。模板方法模式的优点在于其在父类(抽象类)中定义了算法的框架以保障算法的稳定性,同时在父类中实现了算法公共部分的方法来保障代码的复用;将部分算法部分延迟到子类中实现,因此子类可以通过继承的方式来扩展或重新定义算法的功能而不影响算法的稳定性,符合开闭原则。

模板方法模式需要注意抽象类与具体子类之间的协作,在具体使用时包含以下主要角色。

  • 抽象类(Abstract Class)​:定义了算法的框架,由基本方法和模板方法组成。基本方法定义了算法有哪些环节,模板方法定义了算法各个环节执行的流程。
  • 具体子类(Concrete Class)​:对在抽象类中定义的算法根据需求进行不同的实现。

下面以银行办理业务为例实现一个模板方法模式,我们去银行办理业务都要经过抽号、排队、办理业务和评价,其中的业务流程是固定的,但办理的具体业务比较多,比如取钱、存钱、开卡等。其中,办理业务的固定流程就是模板算法中的框架,它常常是不变的,由抽象类定义和实现,而具体办理的业务是可变的部分,通常交给子类去做具体的实现。具体的UML设计如图所示。

在这里插入图片描述
具体实现如下。

(1)定义AbstractTemplate模板类:

public  abstract  class  AbstractTemplate  {
    private  final  static  Log  logger  =
                  LogFactory.getLog(AbstractTemplate.class);
    public void templateMethod(){ //模板方法,用于核心流程和算法的定义
      checkNumber();
      queueUp();
      handleBusiness();
      serviceEvaluation();
    }
    public void checkNumber(){ //1:抽号
    logger.info("checkNumber......");
    }
    public void queueUp(){ //2:排队
      logger.info("queue  up......");
    }
    public abstract void handleBusiness(); //3:业务办理
    public void serviceEvaluation() {//4:服务评价
      logger.info("business  finished, servic  evaluation......");
    }
}

以上代码定义了抽象类AbstractTemplate,用于实现模板方法模式,其中定义了checkNumber()表示抽号过程,queueUp()表示排队过程,handleBusiness()表示需要办理的具体业务,serviceEvaluation()表示在业务办理完成后对服务的评价,templateMethod()定义了银行办理业务的核心流程,即取号、排队、办理业务和评价。抽象类实现了取号、排队、办理业务这些公共方法,而将办理业务的具体方法交给具体的业务类实现。

(2)定义SaveMoney的业务实现:

public  class  SaveMoney  extends  AbstractTemplate  {
    private  final  static  Log  logger  =
              LogFactory.getLog(AbstractTemplate.class);
    @Override
    public  void  handleBusiness()  {
      logger.info("save  money  form  bank.");
    }
}

以上代码定义了SaveMoney并实现了handleBusiness(),以完成存钱的业务逻辑。

(3)定义TakeMoney的业务实现:

public  class  TakeMoney  extends  AbstractTemplate  {
    private  final  static  Log  logger  =
      LogFactory.getLog(AbstractTemplate.class);
    @Override
    public  void  handleBusiness()  {
      logger.info("take  money  form  bank.");
    }
}

以上代码定义了TakeMoney并实现了handleBusiness(),以完成取钱的业务逻辑。

(4)使用模板模式:

public  static  void  main(String[]  args)  {
      //办理取钱流程
      AbstractTemplate  template1  =  new  TakeMoney();
      template1.templateMethod();
      //办理存储流程
      AbstractTemplate  template2  =  new  SaveMoney();
      template2.templateMethod();
  }

在使用模板模式时只需按照需求定义具体的模板类实例并调用其模板方法即可,具体的执行结果如下:

[INFO]  AbstractTemplate  -  checkNumber......
[INFO]  AbstractTemplate  -  queue  up......
[INFO]  AbstractTemplate  -  take  money  form  bank.
[INFO]  AbstractTemplate  -  business  finished, servic  evaluation......
[INFO]  AbstractTemplate  -  checkNumber......
[INFO]  AbstractTemplate  -  queue  up......
[INFO]  AbstractTemplate  -  save  money  form  bank.
[INFO]  AbstractTemplate  -  business  finished, servic  evaluation......

16、观察者模式的概念及Java实现

观察者(Observer)模式指在被观察者的状态发生变化时,系统基于事件驱动理论将其状态通知到订阅其状态的观察者对象中,以完成状态的修改和事件传播。这种模式有时又叫作发布-订阅模式或者模型-视图模式。

观察者模式是一种对象行为型模式,观察者和被观察者之间的关系属于抽象耦合关系,主要优点是在观察者与被观察者之间建立了一套事件触发机制,以降低二者之间的耦合度。

观察者模式的主要角色如下。

  • 抽象主题(Subject)​:持有订阅了该主题的观察者对象的集合,同时提供了增加、删除观察者对象的方法和主题状态发生变化后的通知方法。
  • 具体主题(Concrete Subject)​:实现了抽象主题的通知方法,在主题的内部状态发生变化时,调用该方法通知订阅了主题状态的观察者对象。
  • 抽象观察者(Observer)​:观察者的抽象类或接口,定义了主题状态发生变化时需要调用的方法。
  • 具体观察者(Concrete Observer)​:抽象观察者的实现类,在收到主题状态变化的信息后执行具体的触发机制。

观察者模式具体的UML设计如图所示。

在这里插入图片描述
具体实现如下。

(1)定义抽象主题Subject:

//抽象目标类
  public  abstract  class  Subject  {
    protected  List<Observer>  observers=new  ArrayList<Observer>();
    //增加观察者
    public  void  add(Observer  observer)  {
      observers.add(observer);
    }
    //删除观察者
    public  void  remove(Observer  observer)  {
      observers.remove(observer);
    }
    public abstract void notifyObserver(String message); //通知观察者的抽象方法
}

以上代码定义了抽象主题Subject类,并定义和实现了方法add()、remove()来向Subject添加观察者和删除观察者,定义了抽象方法notifyObserver()来实现在消息发生变化时将变化后的消息发送给观察者。

(2)定义具体的主题ConcreteSubject:

public  class  ConcreteSubject  extends  Subject  {
  private  final  static  Log  logger  =
  LogFactory.getLog(ConcreteSubject.class);
  public  void  notifyObserver(String  message)  {
      for(Object  obs:observers)  {
        logger.info("notify  observer  "+message+"  change...");
        ((Observer)obs).dataChange(message);
      }
  }
}

以上代码定义了ConcreteSubject类,该类继承了Subject并实现了notifyObserver(),用于向观察者发送消息。

(3)定义抽象观察者Observer:

public  interface  Observer  {
  void dataChange(String message); //接收数据
}

以上代码定义了观察者Observer接口并定义了messageReceive(),用于接收ConcreteSubject发送的通知。

(4)定义具体的观察者ConcreteObserver:

public  class  ConcreteSubject  extends  Subject  {
      private  final  static  Log  logger  =
      LogFactory.getLog(ConcreteObserver.class);
    public  void  dataChange(String  message)  {
      logger.info("recive  message:"+message);
    }
}

以上代码定义了具体的观察者ConcreteObserver类,用于接收Observer发送过来的通知并做具体的消息处理。

(5)使用观察者模式:

public  static  void  main(String[]  args)  {
    Subject  subject=new  ConcreteSubject();
    Observer  obs=new  ConcreteObserver();
    subject.add(obs);
    subject.notifyObserver("data1");
}

在使用观察者模式时首先要定义一个Subject主题,然后定义需要接收通知的观察者,接着将观察者加入主题的监控列表中,在有数据发生变化时,Subject(主题)会将变化后的消息发送给观察者,最后调用subject的方法notifyObserver()发送一个数据变化的通知,具体的运行结果如下:

[INFO]  ConcreteSubject  -  notify  observer  data1  change...
[INFO]  ConcreteObserver  -  recive  message:data1

17、迭代器模式的概念及Java实现

迭代器(Iterator)模式提供了顺序访问集合对象中的各种元素,而不暴露该对象内部结构的方法。

Java中的集合就是典型的迭代器模式,比如HashMap,在我们需要遍历HashMap时,通过迭代器不停地获取Next元素就可以循环遍历集合中的所有元素。

迭代器模式将遍历集合中所有元素的操作封装成迭代器类,其目的是在不暴露集合对象内部结构的情况下,对外提供统一访问集合的内部数据的方法。迭代器的实现一般包括一个迭代器,用于执行具体的遍历操作;以及一个Collection,用于存储具体的数据。我们以Collection集合的迭代器设计为例介绍迭代器模式的设计思路。具体的UML设计如图所示。
在这里插入图片描述具体实现如下。

(1)定义名为Collection的集合接口:

public  interface  Collection  {
    //对集合元素的迭代
    public  Iterator  iterator();
    //取得集合元素
    public  Object  get(int  i);
    //向集合添加元素
    public  boolean  add(Object  object);
    //取得集合大小
    public  int  size();
}

以上代码定义了名为Collection的接口,用于制定集合操作的规范。在该接口中定义了iterator()用于集合接口的遍历,定义了get()用于获取集合中的元素,定义了add()用于向集合中添加元素,定义了size()用于获取集合的大小。

(2)定义Collection接口实现类ListCollection:

public  class  ListCollection  implements  Collection{
    public List list = new ArrayList(); //list用于数据的存储
    @Override
    public  Iterator  iterator()  {
      return  new  ConcreteIterator(this);
    }
    @Override
    public  Object  get(int  i)  {
      return  list.get(i);
    }
    @Override
    public  boolean  add(Object  object)  {
      list.add(object);
      return  true;
    }
    @Override
    public  int  size()  {
      return  list.size();
    }
}

以上代码定义了Collection接口的实现类ListCollection,ListCollection类用于存储具体的数据并实现数据操作方法,其中,list用于存储数据,iterator()用于构造集合迭代器。

(3)定义迭代器接口Iterator:

public  interface  Iterator  {
    //指针前移
    public  Object  previous();
    //指针后移
    public  Object  next();
    public  boolean  hasNext();
}

以上代码定义了迭代器接口Iterator,在该接口中规范了迭代器应该实现的方法,其中,previous()用于访问迭代器中的上一个元素,next()用于访问迭代器中的下一个元素,hasNext()用于判断在迭代器中是否还有元素。

(4)定义迭代器接口Iterator的实现类ConcreteIterator:

public  class  ConcreteIterator  implements  Iterator  {
    private  Collection  collection;
    private int pos = -1; //当前迭代器遍历到的元素位置
    public  ConcreteIterator(Collection  collection){
      this.collection  =  collection;
    }
    @Override
    public  Object  previous()  {
      if(pos  >  0){
          pos--;
      }
      return  collection.get(pos);
    }
    @Override
    public  Object  next()  {
      if(pos<collection.size()-1){
          pos++;
      }
      return  collection.get(pos);
    }
    @Override
    public  boolean  hasNext()  {
      if(pos<collection.size()-1){
          return  true;
      }else{
          return  false;
      }
  }
}

以上代码定义了迭代器接口Iterator的实现类ConcreteIterator,在ConcreteIterator中定义了Collection用于访问集合中的数据,pos用于记录当前迭代器遍历到的元素位置,同时实现了在Iterator接口中定义的方法previous()、next()和hasNext(),以完成具体的迭代器需要实现的基础功能。

(5)使用迭代器:

public  static  void  main(String[]  args)  {
  //定义集合
  Collection  collection  =  new  ListCollection();
  //向集合中添加数据
  collection.add("object1");
  //使用迭代器遍历集合
  Iterator  it  =  collection.iterator();
  while(it.hasNext()){
      logger.info(it.next());
  }
 }

迭代器的使用方法比较简单:首先需要定义一个集合并向集合中加入数据,然后获取集合的Iterator迭代器并通过循环遍历集合中的数据。

18、责任链模式的概念及Java实现

责任链(Chain of Responsibility)模式也叫作职责链模式,用于避免请求发送者与多个请求处理者耦合在一起,让所有请求的处理者持有下一个对象的引用,从而将请求串联成一条链,在有请求发生时,可将请求沿着这条链传递,直到遇到该对象的处理器。

在责任链模式下,用户只需将请求发送到责任链上即可,无须关心请求的处理细节和传递过程,所以责任链模式优雅地将请求的发送和处理进行了解耦。

责任链模式在Web请求中很常见,比如我们要为客户端提供一个REST服务,服务端要针对客户端的请求实现用户鉴权、业务调用、结果反馈流程,就可以使用责任链模式实现。

责任链模式包含以下三种角色。

  • Handler接口:用于规定在责任链上具体要执行的方法。
  • AbstractHandler抽象类:持有Handler实例并通过setHandler()和getHandler()将各个具体的业务Handler串联成一个责任链,客户端上的请求在责任链上执行。
  • 业务Handler:用户根据具体的业务需求实现的业务逻辑。

例如,用户鉴权、业务调用、结果反馈流程的责任链实现的具体UML设计如图所示。
在这里插入图片描述
具体实现如下。

(1)定义Handler接口:

public  interface  Handler  {
    void  operator();
}

以上代码定义了Handler接口,该接口用于规定责任链上各个环节的操作,这里定义了operator(),用于在责任链上各个环节处理任务时进行调用。

(2)定义AbstractHandler类:

public  abstract  class  AbstractHandler  {
    private  Handler  handler;
    public  Handler  getHandler()  {
      return  handler;
    }
    public  void  setHandler(Handler  handler)  {
      this.handler  =  handler;
    }
}

以上代码定义了抽象类AbstractHandler来将责任链上的各个组件连接起来,具体操作是通过setHandler()设置下一个环节的组件,通过getHandler()获取下一个环节的组件。

(3)定义用户授权类AuthHandler:

public  class  AuthHandler  extends  AbstractHandler  implements  Handler  {
    private  final  static  Log  logger  =  LogFactory.getLog(AuthHandler.class);
    private  String  name;
    public  AuthHandler(String  name)  {
      this.name  =  name;
    }
    @Override
    public  void  operator()  {
      logger.info("user  auth...");
      if(getHandler()! =null){//执行责任链的下一个流程
          getHandler().operator();
      }
    }
}

以上代码定义了用户授权类AuthHandler并实现了operator(),该方法首先调用当前环节的业务流程,即用户授权,然后通过getHandler()获取下一个组件并调用其operator(),使其执行下一个责任链流程。

(4)定义业务处理类BusinessHandler:

public  class  BusinessHandler  extends  AbstractHandler  implements  Handler  {
    private  final  static  Log  logger  =
              LogFactory.getLog(BusinessHandler.class);
    private  String  name;
    public  BusinessHandler(String  name)  {
      this.name  =  name;
    }
    @Override
    public  void  operator()  {
        logger.info("business  info  handler...");
        if(getHandler()! =null){//执行责任链的下一个流程
          getHandler().operator();
        }
    }
}

以上代码定义了用户授权类BusinessHandler并实现了方法operator(),该方法首先调用当前环节的业务流程,即业务处理流程,然后通过getHandler()获取下一个组件并调用其operator(),使其执行责任链的下一个流程。

(5)定义请求反馈类ResponseHandler:

public  class  ResponseHandler  extends  AbstractHandler  implements  Handler  {
    private  final  static  Log  logger  =
            LogFactory.getLog(ResponseHandler.class);
    private  String  name;
    public  ResponseHandler(String  name)  {
      this.name  =  name;
    }
    @Override
    public  void  operator()  {
      logger.info("message  response...");
      if(getHandler()! =null){//执行责任链的下一个流程
          getHandler().operator();
      }
    }
}

以上代码定义了用户授权类ResponseHandler并实现了operator(),该方法首先调用当前环节的业务流程,这里的业务流程主要是判断业务流程执行的结果并做出相应的反馈,然后通过getHandler()获取下一个组件并调用其operator(),使其执行下一个责任链流程。

(6)使用责任链模式:

public  static  void  main(String[]  args)  {
      AuthHandler   authHandler=  new  AuthHandler("auth");
      BusinessHandler   businessHandler=  new  BusinessHandler("business");
      ResponseHandler   responseHandler=  new  ResponseHandler("response");
      authHandler.setHandler(businessHandler);
      businessHandler.setHandler(responseHandler);
      authHandler.operator();
  }

在使用责任链模式时,首先要定义各个责任链的组件,然后将各个组件通过setHandler()串联起来,最后调用第一个责任链上的operator(),接着程序就像多米诺骨牌一样在责任链上执行下去。具体的执行结果如下:

[INFO]  AuthHandler  -  user  auth...
[INFO]  BusinessHandler  -  business  info  handler...
[INFO]  ResponseHandler  -  message  response...
Java 高级 面试题 及 参考答案 一、面试题基础总结 1、JVM结构原理、GC工作机制详解 答:具体参照:JVM结构、GC工作机制详解 ,说到GC,记住两点:1、GC是负责回收所有无任何引用对象的内存空间。 注意:垃圾回收回收的是无任何引用的对象占据的内存空间而不是对象本身,2、GC回收机制的两种算法,a、引用计数法 b、可达性分析算法(这里的可达性,大家可以看基础2 Java对象的什么周期),至于更详细的GC算法介绍,大家可以参考:Java GC机制算法 2、Java对象的生命周期 答:创建阶段 、 应用阶段 、不... 阅读详情

相关推荐

精确时钟同步协议ptp/IEEE-1588v2协议-------(1)简介

ptp, 1588V2, IEEE-1588, 精确时钟同步协议

meihualing的专栏 5360

Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day30】—— 设计模式1

百日闭关修炼,每日三道高频面试题。一起冲进大厂!今天开始设计模式1,看什么看?快上车!

陈哈哈的菜园子 8179

FREERTOS+LWIP+IAP实现TCP、HTTP、网页访问并固件升级、更新配置 (三)lwip实现httpd服务并在web访问

在前两篇文章中配置freeRTOS和,并实现了TCP、UDP的通信协议,现在终于轮到重头戏lwip的httpd服务,LWIP官方例程中是有很多自带的网页的,但是远远不够满足实际项目的使用需求,因此我也是踩了很多坑,从前端网页制作,到网络通信的实现,到后端数据处理,从头开始学起,也是学习到了很多没接触过的东西,本章将搭建LWIP的HTTP服务使得浏览器可以访问WEB。

wangjiaheng0716的博客 2965

资深Java工程师的面试题目(三)设计模式

以下是针对Java设计模式的面试题,涵盖常见模式的定义、应用场景、代码示例及优缺点分析,适合评估候选人对设计模式的理解和实际应用能力。

刘一说的IT专栏 982

用MATLAB从零实现六足机器人步态仿真:交替三角与波动步态保姆级教程

本文详细介绍了如何使用MATLAB从零实现六足机器人的两种经典步态仿真:交替三角支撑步态和波动步态。通过参数定义、相位设置、运动轨迹生成和三维可视化等步骤,帮助读者掌握六足机器人步态规划的核心技术。教程包含完整代码和详细解析,适合机器人爱好者和相关专业学生学习实践。

weixin_26765363的博客 229

山东大学FPGA课程实验一 加法器设计

电子设计自动化与FPGA设计,实验一 加法器设计

2503_91283667的博客 869

Java面试知识点(全)-设计模式三

Java面试知识点(全)-设计模式三

北巷东东的专栏 893

python 成语接龙-连接数据库

from xpinyin import Pinyin import pymysql while 1: conn = pymysql.connect( host='localhost', #本地连接 user='root', #数据库账户名 password='password', #数据库密码 db='dic',

Hero2902的博客 598

Java设计模式面试题详解

Java设计模式面试题详解

感谢阅读 1451

进阶数据结构——链式前向星

链式前向星是一种进阶的数据结构,主要用于图的存储。我希望大家先看这个视频(蓝色字体点进去) 不然你很难理解的。在图论中,图的存储方式主要有邻接矩阵和邻接表两种。邻接矩阵虽然建图简单方便,但占内存较大,节点数量稍微大点的题目就难以使用(适合稠密图);而邻接表虽然节省空间,但其指针形式难写易错,且vector形式的读取速度较慢,易导致大数据下的超时(TLE)。针对上述问题,链式前向星作为一种折中的方式应运而生。链式前向星本质上是一种静态链表,它将数据以链表形式连接在一起。

ycs66的博客 2137

第四节:Vben Admin登录对接后端getUserInfo接口

上一节,我们完成了/api/auth/login接口的创建,通过login接口,我们完成了登录和Token的生成。但是登陆还是报404返回,发现是Vben Admin又请求了一个/api/getUserInfo接口,本节我们就来分析完成这个接口本节,我们完成了getUserInfo接口,完成了登录操作,成功的进入到工作台页面。

cuiwin的专栏 2846

26个月89场Java岗面试,0至3年程序员的入职门槛到底是什么?

原文链接:https://www.toutiao.com/i6828106271942509067/ 原文作者:Java进阶面霸 来源:头条 今天霸哥要把历时26个月精心准备的大招放出来了。 没错,历时26个月,霸哥共参加了89场面试(不是连续的)。 对于文笔能力比技术还好的霸哥来说,现在随随便便面试一个15k—20k的岗位都不在话下了! 为什么这么说? 同一套技术知识答了89次… 0至3年程序员必备技术集锦 在总结技术知识之前,先给大家看看一些招聘信息: 等等,0~3年Java岗位的要求: .

m0_57285325的博客 1204

uniapp - 实现苹果App打包上架App Store应用商店详细教程,详解Hbuilder打包编译ipa发布上传到苹果ios软件商店全流程,提供云打包/离线本地打包ios、申请IOS苹果证书方法

uni-app,苹果ios,苹果app,打包编译,appstore应用商店,ipa发布到软件商店,uniapp的app苹果应用商店上架,上架苹果APPStore,uniApp打包的ipa文件上传到商店,上架苹果商城,审核失败,被拒绝,UniApp打包ipa文件,上架iOSAppStore流程指南,最新详细教程最全,Hbuilder打包发布iosapp,苹果云打包上线全过程,云打包IPA并上传到商店,打包iOSipa文件后怎么发布到应用商店,苹果证书申请教程,ios证书申请,mac电脑,审核很久

🏆 前端领域优质创作者 1万+

2021年最新Java高级面试和答案

基础是java初学者的起步,都会帮助你从小白入门到精通必学基础课程! 为初学者应该会有很大帮助!入门到入狱,赶紧拿走! Java基础板块知识: 职业规划 学习方法 泛型、容器 数据结构和算法 智能电话本实战 IO流 Java介绍 变量、数据类型、运算符 IDEA 控制语句、方法、递归算法 面向对象 JVM 数组和数据储存 JDK 异常机制、可视化 飞机大战项目 一、面试题基础总结 1、 JVM结构原理、GC工作机制详解? 答:具体参照:JVM结构、G..

m0_59595915的博客 464

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

三天肝完设计模式的面试题,面试再不怕设计模式的问题了!!!(1)

在开头跟大家分享的时候我就说,面试我是没有做好准备的,全靠平时的积累,确实有点临时抱佛脚了,以至于我自己还是挺懊恼的。(准备好了或许可以拿个40k,没做准备只有30k+,你们懂那种感觉吗)如何准备面试?1、前期铺垫(技术沉积)程序员面试其实是对于技术的一次摸底考试,你的技术牛逼,那你就是大爷。大厂对于技术的要求主要体现在:基础,原理,深入研究源码,广度,实战五个方面,也只有将原理理论结合实战才能把技术点吃透。

2401_84419118的博客 1046

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

java面试技巧

可补充面试中未充分说明的技术点(例:附Github调优demo链接)。:synchronized锁升级过程、AQS实现原理、ThreadLocal内存泄漏防范、线程池参数调优。:IoC容器启动流程(Bean生命周期)、动态代理实现(JDK/CGLIB)、事务传播机制。:垃圾回收算法(标记清除/复制/分代收集)、OOM场景诊断、类加载机制。:重点准备二叉树遍历(非递归)、链表反转、Top K问题(堆排序应用):结合项目说明单例模式(DCL实现)、工厂模式在框架中的应用。(停顿5秒),后来还优化了。

leijmdas的专栏 1048

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Java 2024年面试总结(持续更新)

1.自我介绍简单一点吧,把自己的情况说清楚,一两分钟即可。2.微服务的组件答:微服务是把一个类似单体项目根据某种维度进行拆分,比如根据功能模块进行拆分。拆分之后,具备了更好的抗压性/扩展性,还可以更好的解耦,但是维护相比之前会更麻烦了常用的组件有Spring Cloud。其中里面有:Nacos:用来做注册中心/配置中心Gateway:用来做网关Hystrx:做限流、熔断、降级Dubbo:做服务间的调用Feign:也是服务间的调用3.mq的运用。

web18296061989的博客 4805

100道Java高频面试题(阿里面试官整理)

我分享文章的时候,有个读者回复说他去年就关注了我的微信公众号,打算看完我的所有文章,然后去面试,结果我后来很长时间不更新了。。。这次只放出九十道,剩下10道准备找认识的几位面试官去要,希望不会被拒绝。这些题我认为认真思考还是很有价值的,答案整理中,全部整理好,我会做出PDF,整理好后大家公众号后台回复“Java面试题”领取。...

m0_54850825的博客 456

京东Java高开岗三面算法+数据库+设计模式,复习1个月成功拿offer

京东高级java现场三面,包含:算法、数据库、设计模式、java高级等,尾部有最全BAT高级java面试题目和答案福利,想要的就快来领走吧~(领取方式见文末) 京东技术面试(一): 算法面试: 二叉树怎么实现的 知道哪些排序算法 快排怎么实现 堆排序怎么实现 一道算法题:两个有序数组,有相同的元素,找出来 集合类和java高级特性面试 链表,数组的优缺点,应用场景,查找元素的复杂度 hashmap多线程并发情况下有什么问题(就是jdk1.7hashmap成环) Jvm内存模型 Tomcat容器了解吗?

代码界的扛把子 189

面试之路-高级java工程师

作者:纠结哥_Shrek 来源:优快云 原文:https://blog.youkuaiyun.com/weixin_36104843/article/details/88106513 1、背熟你的简历 面试的第一个问题,一般都是让你简单介绍下你自己,或者介绍一下你最近的项目,而一个面试者,如果连自己的简历都无法熟知,对里面提到的项目、技术都无法描述清楚的话,我想没有哪家公司会接受这样的,哪怕你...

Angus 391

2023 年金三银四最新版 Java 面试八股文教程,涵盖 25 大专题:Java 基础 +spring 全家桶 + 大数据 + 网络 + 设计模式 + 算法

每个程序员心中都有一个大厂梦,无论是阿里还是腾讯,对于程序员的技术要求都是比较高的,抛开学历不谈,你的技术水平是否达到了阿里的标准和要求?如果你与其他同行存在着较大的技术差距,而且还没有改变现状的想法,那么被市场所淘汰,只是时间问题。

Park33的博客 176

InnoDB 内存结构总览:Change Buffer、AHI 与 Log Buffer

本文系统梳理InnoDB内存结构中的ChangeBuffer、Adaptive Hash Index(AHI)与LogBuffer。ChangeBuffer缓存二级索引页不在内存时的变更,减少随机IO,仅在页加载时合并;聚簇索引修改立即执行,因数据本身不可延后。AHI基于高频等值查询自动构建哈希索引,加速定位,仅支持等值操作。LogBuffer为redo log内存缓冲,配合磁盘日志实现崩溃恢复。三者均服务于性能优化,其中ChangeBuffer与AHI共享BufferPool空间,而LogBuffer独立

bksczm的博客 292
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值