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