jdk8中接口默認方法,以及在Mybatis中MapperProxy的應用

默認方法的介紹
自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 等等方式)

發佈了11 篇原創文章 · 獲贊 1 · 訪問量 2480
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章