Java反射機制(Reflection )

在說反射之前,讓我們先來想一下這個問題:我們是否能調用某個類的私有方法或者私有成員變量呢???


我相信很多童鞋都會說:不能!


回答“不能”的童鞋,相信理由大家都懂,針對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  好像沒中文版的!點擊打開下載書籍


=================

有空我再寫一些其他反射程序上來,和大家共同學習


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章