我一直以為類的私有構造函數、屬性、方法除了類自身其他類是無法訪問的,前幾天正好學習Spring框架,在學習Spring框架基礎 Bean包時,寫了一個簡單的例子,類似如下:
package study.spring.bean;
public class SimpleBean
{
private String beanName;
private SimpleBean() {
System.out.println( " SimpleBean " );
}
/** */ /**
* @return Returns the beanName.
*/
public String getBeanName()
{
return beanName;
}
/** */ /**
* @param beanName The beanName to set.
*/
public void setBeanName(String beanName)
{
this .beanName = beanName;
}
}
發現居然也能調用成功,當時很驚訝,反射機制平時在以前的項目中也常使用,但不能構造只有私有構造函數的類.
自己做了一個簡單例子:
package study.spring.bean;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class SimpleTest
{
/** *//**
* @param args
*/
public static void main(String[] args)
{
// TODO Auto-generated method stub
try
{
Constructor[] cts=Class.forName("study.spring.bean.SimpleBean").getDeclaredConstructors();
for(int i=0;i<cts.length;i ){
cts[i].newInstance(null);
}
}
catch (SecurityException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InstantiationException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalAccessException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (InvocationTargetException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
也是如我所想 拋出java.lang.IllegalAccessException異常,當時就懷疑Spring框架是否使用反射的一些特性,後來查了相關文檔才知道原因何在:
實際上java在反射創建一個類的實例時,默認會檢測是否符合相關安全,該檢測開關可以關閉.
Constructor、Field、Method都是繼承於AccessibleObject,對應實例調用setAccessible(true)就關閉該開關
如上面的例子,在代碼 cts[i].newInstance(null);行前調用上述方法: cts[i].setAccessible(true);
這樣就可以創建只有構造函數的實例、調用私有構造方法,訪問類的私有屬性.
呵呵,這樣好像java安全性就大大降低.如果你非常注重應用的安全性,java當然考慮到這方面,你可以在JVM啟動參數增加 -Djava.security.manager 啟用安全管理器,如果有該參數,它將檢測正在關閉接入檢測的代碼是否許可了這樣做,上述代碼執行時會拋出java.security.AccessControlException異常.
[火星人 ] Java反射獲取私有構造函數、屬性、方法已經有303次圍觀