參考鏈接: 關于Java中null的有趣事實
java 計算協方差
?
??
? ?
??
??
??
? Java有時可能非常棘手,特別是在API設計中。?
? 讓我們看一個非常有趣的展示柜。?
? jOOQ強烈地將API與實現分開。?
? 所有API都在org.jooq包中,并且是公共的。?
? 大多數實現是在org.jooq.impl包和package-private中。?
? 只有工廠和一些專用的基礎實現是公開的。?
? 這允許非常強大的包級封裝,幾乎只向jOOQ用戶公開接口。?
? ?包級封裝的簡化示例??
? ?大致來說,jOOQ如何建模SQL表。 (過于簡化的)API:??
? package org.jooq;
?
/**
?* A table in a database
?*/
public interface Table {
?
? /**
? ?* Join two tables
? ?*/
? Table join(Table table);
}
? ?還有兩個(過于簡化的)實現類:??
? package org.jooq.impl;
?
import org.jooq.Table;
?
/**
?* Base implementation
?*/
abstract class AbstractTable implements Table {
?
? @Override
? public Table join(Table table) {
? ? return null;
? }
}
?
/**
?* Custom implementation, publicly exposed to client code
?*/
public class CustomTable extends AbstractTable {
}
? ?內部API的公開方式??
? ?假設內部API在協方差方面有一些技巧:??
? abstract class AbstractTable implements Table, InteralStuff {
?
? // Note, this method returns AbstractTable, as it might
? // prove to be convenient to expose some internal API
? // facts within the internal API itself
? @Override
? public AbstractTable join(Table table) {
? ? return null;
? }
?
? /**
? ?* Some internal API method, also package private
? ?*/
? void doThings() {}
? void doMoreThings() {
?
? ? // Use the internal API
? ? join(this).doThings();
? }
}
? ?乍一看,這看起來很安全,是嗎? AbstractTable是包私有的,但CustomTable對其進行了擴展并繼承了其所有API,包括“ AbstractTable join(Table)”的協變方法重寫。 這會導致什么? 查看以下客戶端代碼??
? package org.jooq.test;
?
import org.jooq.Table;
import org.jooq.impl.CustomTable;
?
public class Test {
? public static void main(String[] args) {
? ? Table joined = new CustomTable();
?
? ? // This works, no knowledge of AbstractTable exposed to the compiler
? ? Table table1 = new CustomTable();
? ? Table join1 = table1.join(joined);
?
? ? // This works, even if join exposes AbstractTable
? ? CustomTable table2 = new CustomTable();
? ? Table join2 = table2.join(joined);
?
? ? // This doesn't work. The type AbstractTable is not visible
? ? Table join3 = table2.join(joined).join(joined);
? ? //? ? ? ? ? ? ^^^^^^^^^^^^^^^^^^^ This cannot be dereferenced
?
? ? // ... so hide these implementation details again
? ? // The API flaw can be circumvented with casting
? ? Table join4 = ((Table) table2.join(joined)).join(joined);
? }
}
? ?結論??
? ?篡改類層次結構中的可見性可能很危險。 注意以下事實:在接口中聲明的API方法始終是公共的,而不管涉及非公共偽像的任何協變實現。 如果API設計人員無法正確處理API用戶,這可能會很煩人。??
? ?在下一版的jOOQ中已修復??
? ?參考: Java的深度:在JAVA,SQL和JOOQ博客中, JCG合作伙伴 Lukas Eder 通過協方差暴露了API泄漏 。??
??
?
?
? 翻譯自: https://www.javacodegeeks.com/2012/05/depths-of-java-api-leak-exposed-through.html
?
?java 計算協方差