• java面试干货


    一、mybatis和hibernate有什么不同

      首先无论是mybatis还是hibernate都是通过配置文件,将数据库的表pojo映射起来的。mybatis和hibernate都可以称为ORM(对象关系映射)框架,只是hibernate是完全面向pojo的,而mybatis则不是,hibernate基本不需要编写sql就可以通过映射关系来操作数据库,是一种全表映射的体现,而mybatis则不同,它需要我们提供sql去运行。由于hibernate无须sql,当多表关联超过三个的时候,通过hibernate的级联会造成太多性能的丢失,而且如果查询语句中的子段是根据特定的条件变化的,而hibernate就无法支持这样的变化。

      1.hibernate

        首先通过hibernate的映射文件,将数据库中的表和pojo映射起来,然后通过对pojo操作,从而影响数据库的表。有自己的hql语句,提高效率

      2.mybatis

        首先mybatis提供了使用Mapper的接口编程,只要一个接口和一个xml就能创建映射。mybatis可以自由的书写sql,支持动态的sql,处理列表,动态的生成表名,支持存储过程,这样就可以灵活的定义查询语句,满足各类需求和性能优化的需求,缺点是工作量稍微大于hibernate。

      

    二、java中的设计模式 

      Java 中一般认为有23种设计模式 
      总体来说设计模式分为三大类:
        创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
        结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
        行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

      1.单例者模式(懒汉式和饿汉式)

        所谓的单例设计指的是一个类只允许产生一个实例化对象。 

        饿汉式:构造方法私有化,先创建对象     

          class Singleton {
              /**
              * 在类的内部可以访问私有结构,所以可以在类的内部产生实例化对象
              */
            private static Singleton instance = new Singleton();
              /**
              * private 声明构造
              */
            private Singleton() {

            }
              /**
              * 返回对象实例
              */
            public static Singleton getInstance() {
              return instance;
            }

          }

        懒汉式构造方法私有,当第一使用的时候才去创建对象,存在线程安全问题,所以用到了 synchronized 来实现线程的同步,

          class Singleton {

            /**
            * 声明变量
            */
            private static volatile Singleton singleton = null;

            /**
            * 私有构造方法
            */
            private Singleton() {

            }

            /**
            * 提供对外方法
            */
            public static Singleton getInstance() {
            // 还未实例化
              if (singleton == null) {
                synchronized (Singleton.class) {
                  if (singleton == null) {
                    singleton = new Singleton();
                   }
                }
              }
              return singleton;
            }
          }

      2.工厂设计模式(工厂方法模式和抽象工厂模式)

         1.工厂方法模式      

          (1)普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。

    interface Sender {
    void Send();
    }

    class AppleSender implements Sender {

    @Override
    public void Send() {
    System.out.println("This is apple sender...");
    }
    }

    class BananaSender implements Sender {

    @Override
    public void Send() {
    System.out.println("This is banana sender...");
    }
    }

    public class FactoryPattern {
    public static void main(String[] args) {
    Sender sender = produce("apple");
    sender.Send();
    }
    public static Sender produce(String str) {
    if ("apple".equals(str)) {
    return new AppleSender();
    } else if ("banana".equals(str)) {
    return new BananaSender();
    } else {
    System.out.println("没有该类对象.");
    return null;
    }
    }
    }

          (2) 多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。

    interface Sender {
    void Send();
    }

    class AppleSender implements Sender {

    @Override
    public void Send() {
    System.out.println("This is apple sender...");
    }
    }

    class BananaSender implements Sender {

    @Override
    public void Send() {
    System.out.println("This is banana sender...");
    }
    }

    class SendFactory {
    public Sender produceApple() {
    return new AppleSender();
    }

    public Sender produceBanana() {
    return new BananaSender();
    }
    }

    public class FactoryPattern {
    public static void main(String[] args) {
    SendFactory factory = new SendFactory();
    Sender sender = factory.produceApple();
    sender.Send();
    }
    }      (3) 静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

              就是在上边的类SendFactory中的produceApple()方法前加static,然后在public FactoryPattern中直接调用produceApple()即可

        2.抽象工厂模式     

          工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要扩展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,那么这就用到了抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

    interface Provider {
    Sender produce();
    }

    interface Sender {
    void Send();
    }

    class AppleSender implements Sender {

    @Override
    public void Send() {
    System.out.println("This is apple sender...");
    }
    }

    class BananaSender implements Sender {

    @Override
    public void Send() {
    System.out.println("This is banana sender...");
    }
    }

    class SendAppleFactory implements Provider {

    public Sender produce() {
    return new AppleSender();
    }
    }

    class SendBananaFactory implements Provider {

    public Sender produce() {
    return new BananaSender();
    }
    }


    public class FactoryPattern {
    public static void main(String[] args) {
    Provider provider = new SendAppleFactory();
    Sender sender = provider.produce();
    sender.Send();
    }
    }

       3.建造者模式

        工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种类集中起来管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性。

    public class TicketHelper{

      public void buildAdult(String info){

        System.out.println("构建成年人票逻辑"+info);

      }

     public void buildChildren(String info){

        System.out.println("构建儿童票逻辑"+info);

      }

     public void buildElderly(String info){

        System.out.println("构建老年人票逻辑"+info);

      }

    }

    public class TicketBuilder{

      public static Object builder(TicketHelper helper){

        System.out.println("通过TicketHelper构建套票信息");

      }

      //测试

      public static void mian(String [] args){

        TicketHelper helper=new TicketHepler();

        helper.buildAdult("成人票");

        helper.buildChildren("儿童票");

        helper.buildElderly("老年票");

        Object ticket=TicketBuilder.builder(helper);

      }

    }

      4.装饰者模式

        顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。装饰者模式就是再创一个类来加强主类的功能,这样的话就不用为每个子类创建子类来加强那个子类; 具体方法就是在新创的类中,声明一个主类,就像声明成员变量那样(主类名 变量名),然后重写新类的构造方法, 构造方法中将参数类型设置为主类的类型,然后写要加强的方法。调用时就直接调用新类并创建对象,然后调用新类的方法 就能实现加强的目的。 

     

    interface Shape {
    void draw();
    }

    /**
    * 实现接口的实体类
    */
    class Rectangle implements Shape {

    @Override
    public void draw() {
    System.out.println("Shape: Rectangle...");
    }
    }

    class Circle implements Shape {

    @Override
    public void draw() {
    System.out.println("Shape: Circle...");
    }
    }

    /**
    * 创建实现了 Shape 接口的抽象装饰类。
    */
    abstract class ShapeDecorator implements Shape {
    protected Shape decoratedShape;

    public ShapeDecorator(Shape decoratedShape) {
    this.decoratedShape = decoratedShape;
    }

    @Override
    public void draw() {
    decoratedShape.draw();
    }
    }

    /**
    * 创建扩展自 ShapeDecorator 类的实体装饰类。
    */
    class RedShapeDecorator extends ShapeDecorator {

    public RedShapeDecorator(Shape decoratedShape) {
    super(decoratedShape);
    }

    @Override
    public void draw() {
    decoratedShape.draw();
    setRedBorder(decoratedShape);
    }

    private void setRedBorder(Shape decoratedShape) {
    System.out.println("Border Color: Red");
    }
    }

      5.代理模式(静态代理和动态代理)

        代理模式指给一个对象提供一个代理对象,并由代理对象控制对原对象的引用。代理可以分为静态代理和动态代理。 
    通过代理模式,可以利用代理对象为被代理对象添加额外的功能,以此来拓展被代理对象的功能。可以用于计算某个方法执行时间,在某个方法执行前后记录日志等操作。

        1. 静态代理

          静态代理需要我们写出代理类和被代理类,而且一个代理类和一个被代理类一一对应。代理类和被代理类需要实现同一个接口,通过聚合使得代理对象中有被代理对象的引用,以此实现代理对象控制被代理对象的目的。

    /**
    * 代理类和被代理类共同实现的接口
    */
    interface IService {

    void service();
    }


    /**
    * 被代理类
    */
    class Service implements IService{

    @Override
    public void service() {
    System.out.println("被代理对象执行相关操作");
    }
    }

    /**
    * 代理类
    */
    class ProxyService implements IService{
    /**
    * 持有被代理对象的引用
    */
    private IService service;

    /**
    * 默认代理Service类
    */
    public ProxyService() {
    this.service = new Service();
    }

    /**
    * 也可以代理实现相同接口的其他类
    * @param service
    */
    public ProxyService(IService service) {
    this.service = service;
    }

    @Override
    public void service() {
    System.out.println("开始执行service()方法");
    service.service();
    System.out.println("service()方法执行完毕");
    }
    }


    //测试类
    public class ProxyPattern {

    public static void main(String[] args) {
    IService service = new Service();
    //传入被代理类的对象
    ProxyService proxyService = new ProxyService(service);
    proxyService.service();
    }
    }

        2. 动态代理(jdk动态代理和cglib动态代理)一下使用的jdk动态代理和cglb动态代理的区别就是 jdk动态代理需要一个接口
          JDK 1.3 之后,Java通过java.lang.reflect包中的三个类Proxy、InvocationHandler、Method来支持动态代理。动态代理常用于有若干个被代理的对象,且为每个被代理对象添加的功能是相同的(例如在每个方法运行前后记录日志)。

          动态代理的代理类不需要我们编写,由Java自动产生代理类源代码并进行编译最后生成代理对象。
          创建动态代理对象的步骤:
            1. 指明一系列的接口来创建一个代理对象
            2. 创建一个调用处理器(InvocationHandler)对象
            3. 将这个代理指定为某个其他对象的代理对象
            4. 在调用处理器的invoke()方法中采取代理,一方面将调用传递给真实对象,另一方面执行各种需要的操作

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;

    /**
    * 代理类和被代理类共同实现的接口
    */
    interface IService {
    void service();
    }

    class Service implements IService{

    @Override
    public void service() {
    System.out.println("被代理对象执行相关操作");
    }
    }

    class ServiceInvocationHandler implements InvocationHandler {

    /**
    * 被代理的对象

    *代理对象和被代理对象之间的依赖关系
    */
    private Object srcObject;

    public ServiceInvocationHandler(Object srcObject) {
    this.srcObject = srcObject;
    }

    /**

    *代理逻辑

    */

    @Override
    public Object invoke(Object proxyObj, Method method, Object[] args) throws Throwable {
    System.out.println("开始执行"+method.getName()+"方法");
    //执行原对象的相关操作,容易忘记
    Object returnObj = method.invoke(srcObject,args);
    System.out.println(method.getName()+"方法执行完毕");
    return returnObj;
    }
    }

    public class ProxyPattern {
    public static void main(String[] args) {
    IService service = new Service();
    Class<? extends IService> clazz = service.getClass();

    IService proxyService = (IService) Proxy.newProxyInstance(clazz.getClassLoader(),
    clazz.getInterfaces(), new ServiceInvocationHandler(service));
    proxyService.service();
    }
    }

    三、mybatis执行流程和底层原理

      mybatis执行流程

        1.在lib下导入java包

        2.编写数据库中的表对应的pojo

        3.编写mybatis和核心配置文件(加载mapper映射文件)

        4.编写接口和对应的mapper映射文件(映射文件中的nameSpace是对应的接口的权限定名,查询语句中的id是接口中的方法名,parameterType是接口中方法的参数类型,resultType是接口中的方法的返回值,也可以是resultMap编写的pojo中的成员变量和数据库表字段的对应关系)

        5.然后通过核心配置文件中的mapper和mapper映射文件实现映射器,主要pojo属性和表字段对应,就可以自动映射。

        1.在查询语句中可以使用注解传递多个参数 @param  如果数据过多的话  使用pojo

        2.#和$  如果表名是变化的则必须使用$,order  by 后必须使用$

        3.一对一的级联 在mapper映射文件中 通过association 元素代表一对一级联的开始,property代表映射到的pojo属性,column代表sql列,select配置对应的命名空间,这样便可以指出对应mapper的sql,mybatis就会通过对应的sql将数据查询回来

          <asscoiation property="task" column="task_id"  select="task的mapper的接口的全路径名称下的要查询的那个方法"  /asscoiation>

          一对多的级联 在mapper映射文件中 通过collection配置,并且在pojo中 一的一方配置多的一方的组合用集合的方式,property代表一的一方中组合的属性名,

        4.延迟加载  lazyLoadingEnabled默认是false,和 aggressiveLazyLoading 默认false

        5.动态sql,choose,when,otherwise, trim, where,set,foreach

      底层原理

        通过动态代理实现mapper自动映射

    四、Spring (spring IOC 和 Spring AOP)

        spring依赖注入的三种方式:1.构造器注入   2.setter注入    3.接口注入  

        spring装配bean的三种方式:1.在xml中显示配置    2.在java接口和类中实现配置     3.隐式Bean的发现机制和自动装配原则

          使用xml装配bean,只需要在配置文件中编写 bean标签,里边配置property  的name 和 value

          通过注解装配bean,@Component,代表 spring ioc会把这个类扫描成bean实例,这样spring ioc 并不知道去哪里扫描,所以就有@ComponentScan   代表全表扫描,默认是当前包的路径。   -----这个一般不使用

            @Autowired(required="false|true")默认是true就是必须注入成功, 自动装配,如果一个接口下不只有一个实现类的话,使用在动装配存在歧义,所以使用@Primary和@Qualifier,注解@Primary写在具体的实现类上,代表这个类优先注入,但是这并不能解决实际问题,可以 使用@Qualifier(“在具体的实现类中起的别名”)写在@Autowired的下边

          Spring IOC 底层采用是反射,IOC的设计是基于BeanFactory

  • 相关阅读:
    glog入门demo
    gflag的简单入门demo
    caffe库源码剖析——net层
    排序算法的c++实现——计数排序
    docker的/var/lib/docker目录迁移
    SpringCloud Ribbon 负载均衡 通过服务器名无法连接的神坑一个
    Spring Boot Cache使用与整合
    Navicat Keygen
    Windows / Office
    docker swarm 搭建与服务更新
  • 原文地址:https://www.cnblogs.com/xp0813/p/11310932.html
Copyright © 2020-2023  润新知