jdk8中接口默认方法,以及在Mybatis中MapperProxy的应用

好久不见. 提交于 2020-01-20 20:52:15

默认方法的介绍
自jdk8开始接口中可以声明default方法。
oracle官网jdk各个版本更新信息的地址:https://docs.oracle.com/en/java/javase/index.html

jdk8中对新增的默认方法的介绍:官网介绍连接
Default methods enable new functionality to be added to the interfaces of libraries and ensure binary compatibility with code written for older versions of those interfaces.

默认方法允许将新功能添加到库的接口,并确保与为这些接口的较早版本编写的代码二进制兼容。

默认方法的原理
default声明的方法编译后实际上是public修饰的非abstract方法

//声明接口
public interface Java8interface {

    int num = 100;

    void Method();

    default void defaultMethod() {
        System.out.println("I am default method!");
    }

}

//反编译结果 
//默认修饰符
//方法:public abstract 
//默认方法:public 
//属性: public static final
public interface Java8interface
{

    public abstract void Method();

    public void defaultMethod()
    {
        System.out.println("I am default method!");
    }

    public static final int num = 100;
}

Method类中对default方法的判断代码

/oracle jdk1.8 Method类中isDefault()方法,判断是否是接口中的默认方法
public boolean isDefault() {
    
    // Default methods are public non-abstract instance methods
    // declared in an interface.
    // 默认方法就是在接口中声明的 public 非 abastract 的实例方法
    
    //运算过程
    //((getModifiers() & (0b000110010000 | 0b0001 | 0b1000)) == 0b0001)
    //(getModifiers() & 0b000110011001) == 0b0001)
    //逻辑与运算结果:如果方法修饰符是public(0b0001) 返回true,否则返回false
    return ((getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
            Modifier.PUBLIC) && getDeclaringClass().isInterface();
    
}

//Modifier类常见的修饰符对应的int值
//public
public static final int PUBLIC           = 0x00000001;//0b0001
//private
public static final int PRIVATE          = 0x00000002;//0b0010
//protected
public static final int PROTECTED        = 0x00000004;//0b0100
//static
public static final int STATIC           = 0x00000008;//0b1000
//final
public static final int FINAL            = 0x00000010;//0b1010
//synchronized
public static final int SYNCHRONIZED     = 0x00000020;//0b00010100
//volatile
public static final int VOLATILE         = 0x00000040;//0b00101000
//transient
public static final int TRANSIENT        = 0x00000080;//0b01010000
//native
public static final int NATIVE           = 0x00000100;//0b01100100
//interface
public static final int INTERFACE        = 0x00000200;//0b11001000
//abstract
public static final int ABSTRACT         = 0x00000400;//0b000110010000
//strictfp
public static final int STRICT           = 0x00000800;//0b001100100000

在Mybatis中Default方法的使用
在源码MapperProxy类中的invoke方法代码如下:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

	//执行操作之前的判断
    try {
      //判断是否是Object中的方法
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (method.isDefault()) {//调用Method类中的idDefault方法判断是否是接口中的默认方法
      	//privateLookupInMethod 判断MethodHandles类中是否有privateLookupIn方法,该方法是java9中才有的
        if (privateLookupInMethod == null) {
          return invokeDefaultMethodJava8(proxy, method, args);
        } else {
          return invokeDefaultMethodJava9(proxy, method, args);
        }
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }

	//这个代码的作用暂时没深入研究,有知道的欢迎分享
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    
    //execute执行增删查改操作
    return mapperMethod.execute(sqlSession, args);
  }

MapperProxy 介绍
Mybatis的基本使用

    public static void main(String[] args) throws Exception {
		//1、加载配置文件
        InputStream inputStream  = Resources.getResourceAsStream("mybatis-config.xml");
		//2、获取SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		//3、通过SqlSessionFactory 获取SqlSession 
        SqlSession session = sqlSessionFactory.openSession();
		//4、通过SqlSession获取mapper 接口
        EmpMapper mapper = session.getMapper(EmpMapper.class);
		//5、调用mapper接口方法
        List<Emp> empList = mapper.queryEmp();
		//6、输出结果
        for (Emp e:empList
             ) {
            System.out.println(e);
        }
        //7、关闭
        inputStream.close();
        session.close();
    }

问题:
第5步中为什么能调用接口的方法,获取到数据?

原理:
第4步中getMapper方法实际上是返回MapperProxy对象,该对象对mapper接口进行代理(jdk代理、CGlib 等等方式)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!