在說反射之前,讓我們先來想一下這個問題:我們是否能調用某個類的私有方法或者私有成員變量呢???
我相信很多童鞋都會說:不能!
回答“不能”的童鞋,相信理由大家都懂,針對private的成員變量,只允許當前類的方法對其進行調用,這也就是封裝的思想!但是童鞋們可能忽略了一個在Java中蠻重要的機制——反射機制!
而我對上面的問題回答是肯定的!
讓我們來看一下Java反射機制主要提供了哪些功能:
1、在運行時可以判斷任意的對象其所屬的類;
2、在運行時可以構造任意一個類的對象;
3、在運行時可以判斷任意一個類,其所擁有的成員變量和方法;
4、在運行時可以調用任意一個對象的方法。
因此,我們可以在程序運行時通過Reflection的APIs獲取任意一個已經知道名稱的類的內部信息,例如modifiers、fields、methods(不能獲取到方法內的實現,也就是代碼)、superclass和interfaces,更先進的是我們可以在程序運行時,通過APIs去改變fields的值或者調用methods!
所以Java也可以被認爲是動態或準動態語言!(程序在運行的時候,可以改變程序結構或變量類型,這種語言稱爲動態語言)
我們來看一下JDK,主要由以下類來實現Java的反射機制的:
java.lang包下的有:
Class類:代表一個類;
java.lang.reflect包下的有:
Array類:提供了動態創建數組,以及訪問數組元素的靜態方法;
Constructor類:代表類的構造方法;
Field類:代表類的成員變量;
Method類:代表類的方法。
介紹完了基本信息,讓我們來看一下代碼,以下代碼段的功能是,讀取參數指定的類名,然後打印該類所具有的方法:
注意上面的註釋,每個class對象都對應着一個Class類;查看源碼會發現,Class類的構造方法的modifier卻是private的,也就是說,我們並不能像一般類用new去實例化該類的對象,因此,創建Class類,是JVM的“職責”!
所輸入的參數爲:
輸出的結果爲:
public boolean java.lang.String.equals(java.lang.Object)
public java.lang.String java.lang.String.toString()
public int java.lang.String.hashCode()
public int java.lang.String.compareTo(java.lang.String)
public int java.lang.String.compareTo(java.lang.Object)
public int java.lang.String.indexOf(int)
public int java.lang.String.indexOf(int,int)
public int java.lang.String.indexOf(java.lang.String)
public int java.lang.String.indexOf(java.lang.String,int)
static int java.lang.String.indexOf(char[],int,int,char[],int,int,int)
public static java.lang.String java.lang.String.valueOf(int)
public static java.lang.String java.lang.String.valueOf(char)
public static java.lang.String java.lang.String.valueOf(boolean)
public static java.lang.String java.lang.String.valueOf(float)
public static java.lang.String java.lang.String.valueOf(char[],int,int)
public static java.lang.String java.lang.String.valueOf(double)
public static java.lang.String java.lang.String.valueOf(char[])
public static java.lang.String java.lang.String.valueOf(java.lang.Object)
public static java.lang.String java.lang.String.valueOf(long)
public char java.lang.String.charAt(int)
private static void java.lang.String.checkBounds(byte[],int,int)
public int java.lang.String.codePointAt(int)
public int java.lang.String.codePointBefore(int)
public int java.lang.String.codePointCount(int,int)
public int java.lang.String.compareToIgnoreCase(java.lang.String)
public java.lang.String java.lang.String.concat(java.lang.String)
public boolean java.lang.String.contains(java.lang.CharSequence)
public boolean java.lang.String.contentEquals(java.lang.CharSequence)
public boolean java.lang.String.contentEquals(java.lang.StringBuffer)
public static java.lang.String java.lang.String.copyValueOf(char[])
public static java.lang.String java.lang.String.copyValueOf(char[],int,int)
public boolean java.lang.String.endsWith(java.lang.String)
public boolean java.lang.String.equalsIgnoreCase(java.lang.String)
public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[])
public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[])
public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException
public void java.lang.String.getBytes(int,int,byte[],int)
public byte[] java.lang.String.getBytes()
public byte[] java.lang.String.getBytes(java.nio.charset.Charset)
public void java.lang.String.getChars(int,int,char[],int)
void java.lang.String.getChars(char[],int)
public native java.lang.String java.lang.String.intern()
public boolean java.lang.String.isEmpty()
public int java.lang.String.lastIndexOf(java.lang.String)
public int java.lang.String.lastIndexOf(int,int)
public int java.lang.String.lastIndexOf(int)
public int java.lang.String.lastIndexOf(java.lang.String,int)
static int java.lang.String.lastIndexOf(char[],int,int,char[],int,int,int)
public int java.lang.String.length()
public boolean java.lang.String.matches(java.lang.String)
public int java.lang.String.offsetByCodePoints(int,int)
public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int)
public boolean java.lang.String.regionMatches(int,java.lang.String,int,int)
public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence)
public java.lang.String java.lang.String.replace(char,char)
public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String)
public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String)
public java.lang.String[] java.lang.String.split(java.lang.String)
public java.lang.String[] java.lang.String.split(java.lang.String,int)
public boolean java.lang.String.startsWith(java.lang.String)
public boolean java.lang.String.startsWith(java.lang.String,int)
public java.lang.CharSequence java.lang.String.subSequence(int,int)
public java.lang.String java.lang.String.substring(int)
public java.lang.String java.lang.String.substring(int,int)
public char[] java.lang.String.toCharArray()
public java.lang.String java.lang.String.toLowerCase()
public java.lang.String java.lang.String.toLowerCase(java.util.Locale)
public java.lang.String java.lang.String.toUpperCase()
public java.lang.String java.lang.String.toUpperCase(java.util.Locale)
public java.lang.String java.lang.String.trim()
我們先來看一下,使用傳統方法,調用另一個類的私有方法,會提示些啥:
package com.gdut.reflection;
public class PrivateMethod {
private void privateMethod() {
System.out.println("通過java反射機制,調用了class PrivateMethod的私有方法");
}
}
這樣調用PrivateMethod類的privateMethod方法,提示方法不可見!
現在我們通過反射機制,調用另外一個類的私有方法:
還是調用上面PrivateMethod類的privateMethod方法,代碼如下:
package com.gdut.reflection;
import java.lang.reflect.Method;
public class PrivateTest {
private static void invocation(Object obj) throws Exception {
// 獲得obj的Class類
Class<?> cls = obj.getClass();
// 獲得類的私有方法
// 參數:第一個爲方法名; 第二個爲方法參數數組, 此處爲空
Method method = cls.getDeclaredMethod("privateMethod", new Class[] {});
// 調用private方法的關鍵一句話,沒有設置就會報錯
method.setAccessible(true);
// 調用obj的method方法,method方法的參數列表爲第二個參數指定
method.invoke(obj, new Object[] {});
}
public static void main(String[] args) throws Exception {
PrivateTest.invocation(new PrivateMethod());
}
}
輸出結果:
這樣做(調用其他類的私有方法),是否和封裝的思想相悖呢???哈哈,仁者見仁,智者見智!!
推薦大家看一下書:Manning - java reflection in action 好像沒中文版的!點擊打開下載書籍
=================
有空我再寫一些其他反射程序上來,和大家共同學習