文章轉載自「開發者圓桌」一個10年老猿原創文章傳播開發經驗,尤其適合初學者或剛入職場前幾年程序猿的微信公衆號。
之前推送了一篇叫做「你真的會寫單例模式嗎?」的文章,裏面提到一個觀點:“可能會有人使用反射強行調用我們的私有構造器”,看到在我們的開發者圓桌QQ交流羣162566098中,很多童鞋不明白Java反射機制怎麼做到調用私有構造器,今天我們來做一個實驗。
實驗代碼
import java.lang.reflect.*;
public class ReflectTest {
public static void main(String[] args) throws Exception {
//get Constructor
Class clazz = Class.forName("TestOne");
Constructor cons = clazz.getDeclaredConstructor(null);
//set accessible to access private constructor
cons.setAccessible(true); //1
cons.newInstance(null);
cons.newInstance(null);
}
}
class TestOne {
private TestOne() {
System.out.println("init TestOne=="+this.hashCode());
}
}
實驗結果
註釋1處的代碼cons.setAccessible(true),執行main函數,出現異常Exception in thread "main" java.lang.IllegalAccessException: Class ReflectTest can not access a member of class TestOne with modifiers "private"
開啓1處的代碼cons.setAccessible(true),執行main函數,出現如下正常的初始化信息:
init TestOne==12677476
init TestOne==33263331
這說明私有構造函數被多次成功調用,注意是私有構造函數哦。
實驗總結
出現完全不同的兩種測試結果的原因是什麼?我們來剖析一下cons.setAccessible(true)函數,爲什麼設置爲true時,可以通過反射調用私有構造器呢?我們定位到cons.setAccessible(true)源代碼,可以看到下面的英文說明,右側已經幫助大家翻譯了一下。
也就是說,Java反射機制非常強大,可以根據需要繞過Java語言的訪問檢查。
原文是這樣說的:
Set the <tt>accessible</tt> flag for this object to the indicated boolean value. A value of <tt>true</tt> indicates that the reflected object should suppress Java language access checking when it is used. A value of <tt>false</tt> indicates that the reflected object should enforce Java language access checks.
翻譯過來是這樣的:
將此對象的<tt>可訪問</ tt>標誌設置爲指示的布爾值。 值<tt> true </ tt>表示反射對象應該在使用時抑制Java語言訪問檢查。 值<tt> false </ tt>表示反射對象應強制實施Java語言訪問檢查。