Java之反射四大核心類Class/Constructor/Method/Field

首先什麼是反射?反射指的是對象的反向操作,先通過以下代碼看看什麼是正向操作。

package www.bit.java.reflect;
import java.util.Date;
public class Test {
	public static void main(String[] args) {
		//正向操作:1.先導入要使用的包  2.通過new實例化一個類的對象
		Date date=new Date();
		System.out.println(date);
	}
}

以上代碼就是一個典型的正向操作,對於類的使用是通過包名.類名找到該類。而反向操作指的是根據類的實例化對象來取得類的相關信息。

注:在反射的世界裏,注重的不再是實例化對象而是對象所對應的類的信息(如類名、構造方法、普通方法、屬性等)。

1. Class類

Class類是系統提供的一個類,用於描述類的類,即描述具體類的信息的一個類。Class類對象由JVM產生,當類進行加載時,JVM就會產生該類的Class類對象,並且需要注意的是任何一個類都只有一個Class類對象。

1.1 Class類對象的三種實例化方式

(1)調用Object類的getClass()方法,任何類的實例化對象通過調用Object類的getClass()方法都可以取得其Class類對象。

public final native Class<?> getClass();

該方法是Object類的方法,用於取得Class類的對象,即取得調用該方法的對象對應的類的Class類對象。演示如下:

package www.bit.java.reflect;
import java.util.Date;
public class Test {
	public static void main(String[] args) {
		Date date=new Date();
		//調用getClass()方法取得Class類的對象
		Class<?> dateClass=date.getClass();
		System.out.println(dateClass);
	}
}

運行結果爲:

class java.util.Date

此時,通過調用getClass()方法取得了Date類的Class類對象,而該Class類對象用於描述Date類的信息。即通過對象取得了對象的來源,即取得了對象所對應的類的信息。

(2)類.class,即直接根據具體類名稱.class取得對應類的Class類對象。

package www.bit.java.reflect;
import java.util.Date;
public class Test {
	public static void main(String[] args) {
		//通過具體類名稱.class取得具體類對應的Class類對象
		Class<?> dateClass=Date.class;
		System.out.println(dateClass);
	}
}

運行結果爲:

class java.util.Date

(3)調用Class類的類方法forName()方法。

forName()方法的源代碼如下:

@CallerSensitive
    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        Class<?> caller = Reflection.getCallerClass();
        return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
    }

通過源代碼可以看出:forName()方法是Class類的類方法,傳入的參數爲具體的類的全名。演示如下:

package www.bit.java.reflect;
class Fruit{ //自定義類
	
}
public class Test {
	public static void main(String[] args) throws ClassNotFoundException {
		//通過Class類的類方法forName()實例化具體類的Class類對象
		Class<?> fruitClass=Class.forName("www.bit.java.reflect.Fruit");
		System.out.println(fruitClass);
	}
}

運行結果如下:

class www.bit.java.reflect.Fruit

通過以上三種方式都可以取得具體類的Class類對象,但是使用getClass()方法時需要先產生具體類的實例化對象,而另外兩種不需要產生具體類的實例化對象也可以取得其Class類對象。

那麼可不可以通過Class類對象從而實例化具體類的實例化對象呢?答案是肯定的。

1.2 通過反射實例化具體類的對象

通過反射實例化具體類的對象,調用的是Class類的newInstance()方法。演示如下:

package www.bit.java.reflect;
import java.util.Date;
public class Test {
	public static void main(String[] args) throws Exception {
		//通過反射實例化具體類Date的對象:1.先產生具體類的Class類對象  2.調用Class類的newInstance()方法
		Class<?> cls=Class.forName("java.util.Date");
		Object obj=cls.newInstance();
		System.out.println(obj);
		//以上通過反射實例化具體類的對象相當於以下操作:
		Date date=new Date();
		System.out.println(date);
	}
}

運行結果如下:

Sat May 12 10:35:16 CST 2018
Sat May 12 10:35:16 CST 2018

故,實例化具體類的對象有了兩種方式:1.通過new關鍵字   2.通過反射

但需要注意的是:使用newInstance()方法的前提是該具體類具有無參的構造方法,因爲newInstance()方法實質上是在其內部默認調用了該具體類的無參構造方法。若該具體類沒有無參構造方法而調用了newInstance()方法後,則出現異常。演示如下:

package www.bit.java.reflect;
class Fruit{
	//自定義一個有參的構造方法,則系統默認提供的無參構造方法無效
	public Fruit(String msg){
		System.out.println(msg);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		Class<?> cls=Class.forName("www.bit.java.reflect.Fruit");
		Object obj=cls.newInstance();
		System.out.println(obj);
	}
}

運行時出現異常:

Exception in thread "main" java.lang.InstantiationException: www.bit.java.reflect.Fruit
	at java.lang.Class.newInstance(Unknown Source)
	at www.bit.java.reflect.Test.main(Test.java:12)
Caused by: java.lang.NoSuchMethodException: www.bit.java.reflect.Fruit.<init>()
	at java.lang.Class.getConstructor0(Unknown Source)
	... 2 more

1.3 通過反射取得父類信息

在java中任何一個程序類都有父類,因爲任何類都繼承於Object類。

(1)取得類的包名稱-------Class類的getPackage()方法

getPackage()方法的源代碼如下:

 public Package getPackage(); 

調用getPackage()方法如下:

package www.bit.java.reflect;
//自定義接口
interface Fruit{}
//自定義類
class Message{}
//自定義子類
class Apple extends Message implements Fruit{}

public class Test {
	public static void main(String[] args) throws Exception {
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		Object obj=cls.getPackage();
		System.out.println(obj);
	}
}

運行結果如下:

package www.bit.java.reflect

(2)取得父類的Class類對象-------Class類的getSuperclass()方法

getSuperclass()方法的源代碼如下:

public native Class<? super T> getSuperclass();

調用getSuperclass()方法如下:

package www.bit.java.reflect;
//自定義接口
interface Fruit{}
//自定義類
class Message{}
//自定義子類
class Apple extends Message implements Fruit{}

public class Test {
	public static void main(String[] args) throws Exception {
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		Class<?> superClass=cls.getSuperclass();
		System.out.println(superClass);
	}
}

運行結果如下:

class www.bit.java.reflect.Message

(3)取得實現的父接口------Class類的getInterfaces()方法

getInterfaces()方法的源代碼如下:

public Class<?>[] getInterfaces();

該方法返回的是數組,該數組中存放的是該類實現的所有父接口。

調用getInterfaces()方法如下:

package www.bit.java.reflect;
//自定義接口1
interface Fruit{}
//自定義接口2
interface Drink{}
//自定義接口3
interface Eat{}
//自定義類
class Message{}
//自定義子類
class Apple extends Message implements Fruit,Drink,Eat{}

public class Test {
	public static void main(String[] args) throws Exception {
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		Class<?>[] superInterface=cls.getInterfaces();
		for (Class<?> class1 : superInterface) {
			System.out.println(class1);
		}
	}
}

運行結果如下:

interface www.bit.java.reflect.Fruit
interface www.bit.java.reflect.Drink
interface www.bit.java.reflect.Eat

2. Constructor類

Constructor類是描述一個具體類中所有構造方法的類。一個類中可以存在多個構造方法,若想取得類中構造方法,使用的是Class類提供的以下方法:

2.1 取得指定參數類型的構造方法

(1)Class類的getConstructor()方法

該方法取得具體類的指定參數類型的public權限的構造方法。

getConstructor()方法的源代碼如下:

public Constructor<T> getConstructor(Class<?>... parameterTypes);

返回類型爲Constructor類的對象,參數類型爲指定參數類型的構造方法的參數的Class類對象。

調用getConstructor()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Constructor;

class  Fruit{
	//public權限的構造方法
	public Fruit(String msg) {
		System.out.println(msg);
	}
	//private權限的構造方法
	private Fruit(int num) {
		System.out.println(num);
	}
	//default權限的構造方法
	Fruit(String msg,int num) {
		System.out.println(msg);
		System.out.println(num);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		Class<?> cls=Class.forName("www.bit.java.reflect.Fruit");
		//調用Class類的getConstructor()方法取得指定參數類型的public權限的構造方法
		Constructor<?> cons=cls.getConstructor(String.class);
		System.out.println(cons);
	}
}

運行結果如下:

public www.bit.java.reflect.Fruit(java.lang.String)

要注意的是:getConstructor()方法只能取得指定參數類型的public權限的構造方法,不能取得其他權限的構造方法,否則會出現異常。演示如下:

package www.bit.java.reflect;
import java.lang.reflect.Constructor;

class  Fruit{
	//public權限的構造方法
	public Fruit(String msg) {
		System.out.println(msg);
	}
	//private權限的構造方法
	private Fruit(int num) {
		System.out.println(num);
	}
	//default權限的構造方法
	Fruit(String msg,int num) {
		System.out.println(msg);
		System.out.println(num);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		Class<?> cls=Class.forName("www.bit.java.reflect.Fruit");
		//調用Class類的getConstructor()方法取得指定參數類型的private權限的構造方法
		//此時會出現異常
		Constructor<?> cons=cls.getConstructor(int.class);
		System.out.println(cons);
	}
}

運行時出現異常:

Exception in thread "main" java.lang.NoSuchMethodException: www.bit.java.reflect.Fruit.<init>(java.lang.String, int)
	at java.lang.Class.getConstructor0(Unknown Source)
	at java.lang.Class.getConstructor(Unknown Source)
	at www.bit.java.reflect.Test.main(Test.java:24)

(2)Class類的getDeclaredConstructor()方法

該方法可以取得具體類的指定參數類型的任意權限的構造方法。

getDeclaredConstructor()方法的源代碼如下:

public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

返回類型爲Constructor類的對象,參數類型爲指定參數類型的構造方法的參數的Class類對象。

調用getDeclaredConstructor()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Constructor;

class  Fruit{
	//public權限的構造方法
	public Fruit(String msg) {
		System.out.println(msg);
	}
	//private權限的構造方法
	private Fruit(int num) {
		System.out.println(num);
	}
	//default權限的構造方法
	Fruit(String msg,int num) {
		System.out.println(msg);
		System.out.println(num);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		Class<?> cls=Class.forName("www.bit.java.reflect.Fruit");
		//調用Class類的getDeclaredConstructor()方法取得指定參數類型的任意權限的構造方法
		//取得public權限的構造方法
		Constructor<?> cons1=cls.getDeclaredConstructor(String.class);
		//取得private權限的構造方法
		Constructor<?> cons2=cls.getDeclaredConstructor(int.class);
		//取得default權限的構造方法
		Constructor<?> cons3=cls.getDeclaredConstructor(String.class);
		System.out.println(cons1);
		System.out.println(cons2);
		System.out.println(cons3);
	}
}

運行結果如下:

public www.bit.java.reflect.Fruit(java.lang.String)
private www.bit.java.reflect.Fruit(int)
public www.bit.java.reflect.Fruit(java.lang.String)

故,getConstructor()方法與getDeclaredConstructor()方法的區別在於:

(1)getConstructor()方法只能取得指定參數類型的public權限的構造方法,不能取得其他權限的構造方法,否則會出現異常。

(2)getDeclaredConstructor()方法可以取得具體類的指定參數類型的任意權限的構造方法。

2.2 取得類中所有構造方法

(1)Class類的getConstructors()方法

該方法用於取得具體類中權限爲public的構造方法。

getConstructors()方法的源代碼如下:

    public Constructor<?>[] getConstructors() throws SecurityException

調用getConstructors()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Constructor;

class  Fruit{
	//public權限的構造方法
	public Fruit(String msg) {
		System.out.println(msg);
	}
	//public權限的構造方法
	public Fruit(String msg1,String msg2) {
		System.out.println(msg1);
		System.out.println(msg2);
	}
	//private權限的構造方法
	private Fruit(int num) {
		System.out.println(num);
	}
	//default權限的構造方法
	Fruit(String msg,int num) {
		System.out.println(msg);
		System.out.println(num);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		Class<?> cls=Class.forName("www.bit.java.reflect.Fruit");
		//調用Class類的getConstructors()方法取得權限爲public的構造方法
		Constructor<?>[] cons=cls.getConstructors();
		for (Constructor<?> constructor : cons) {
			System.out.println(constructor);
		}
	}
}

運行結果如下:

public www.bit.java.reflect.Fruit(java.lang.String,java.lang.String)
public www.bit.java.reflect.Fruit(java.lang.String)

故,getConstructors()方法只能取得具體類的public權限的構造方法。

(2)Class類的getDeclaredConstructors()方法

該方法用於取得具體類的所有構造方法。

getDeclaredConstructors()方法的源代碼如下:

public Constructor<?>[] getDeclaredConstructors() throws SecurityException

調用getDeclaredConstructors()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Constructor;

class  Fruit{
	//public權限的構造方法
	public Fruit(String msg) {
		System.out.println(msg);
	}
	//public權限的構造方法
	public Fruit(String msg1,String msg2) {
		System.out.println(msg1);
		System.out.println(msg2);
	}
	//private權限的構造方法
	private Fruit(int num) {
		System.out.println(num);
	}
	//default權限的構造方法
	Fruit(String msg,int num) {
		System.out.println(msg);
		System.out.println(num);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		Class<?> cls=Class.forName("www.bit.java.reflect.Fruit");
		//調用Class類的getDeclaredConstructors()方法取得所有構造方法
		Constructor<?>[] cons=cls.getDeclaredConstructors();
		for (Constructor<?> constructor : cons) {
			System.out.println(constructor);
		}
	}
}

運行結果如下:

www.bit.java.reflect.Fruit(java.lang.String,int)
private www.bit.java.reflect.Fruit(int)
public www.bit.java.reflect.Fruit(java.lang.String,java.lang.String)
public www.bit.java.reflect.Fruit(java.lang.String)

故,getConstructors()方法與getDeclaredConstructors()方法的區別在於:

(1)getConstructors()方法只能取得public權限的構造方法,不能取得其他權限的構造方法。

(2)getDeclaredConstructors()方法可以取得具體類的所有構造方法。

2.3 通過反射取得構造方法實例化對象--------Constructor類的newInstance()方法

利用Constructor類取得的構造方法,從而調用newInstance()方法實例化對象。

Constructor類的newInstance()方法的源代碼如下:

 public T newInstance(Object ... initargs)

返回類型爲泛型,最終通過類型擦除爲Object類,參數類型爲可變參數,傳入需要調用的構造方法的參數類型。

調用newInstance()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Constructor;

class  Fruit{
	//public權限的構造方法
	public Fruit(String msg) {
		System.out.println(msg);
	}
	@Override
	public String toString() {
		return "Fruit [toString()=" + super.toString() + "]";
	}	
}
public class Test {
	public static void main(String[] args) throws Exception {
		Class<?> cls=Class.forName("www.bit.java.reflect.Fruit");
		//調用Class類的getDeclaredConstructor()方法取得構造方法
		Constructor<?> cons=cls.getDeclaredConstructor(String.class);
		Object obj=cons.newInstance("調用Constructor類的newInstance()方法");
		System.out.println(obj);
	}
}

運行結果如下:

調用Constructor類的newInstance()方法
Fruit [toString()=www.bit.java.reflect.Fruit@70dea4e]
總結:之前Class類通過反射(利用Class類的newInstance()方法)實例化類對象時,只能夠調用類的無參構造方法,若具體類中沒有無參構造方法則不能使用Class類的newInstance()方法。而是通過反射取得具體需要實例化時調用的構造方法並利用Constructor類提供的newInstance()方法實例化對象。

3. Method類

既然可以通過反射取得構造方法,那麼也有通過反射操作取得普通方法的方式。Method類就是用來描述具體類的普通方法的類。下面介紹如何通過反射取得普通方法。

3.1 取得指定普通方法

(1)Class類的getMethod()方法

該方法的功能爲根據方法名以及參數取得指定的權限爲public的普通方法。

getMethod()方法的源代碼如下:

    public Method getMethod(String name, Class<?>... parameterTypes)

返回類型爲Method類對象,第一個參數爲字符串,表示方法名稱;第二個參數爲可變參數,表示該方法名所對應的參數類型的Class類對象。

調用getMethod()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Method;

class  Fruit{
	//public權限的普通方法
	public void fun1(String msg) {
		System.out.println(msg);
	}
	//private權限的普通方法
	private void fun2(int num) {
		System.out.println(num);
	}
	//default權限的普通方法
	void fun3(String msg,int num) {
		System.out.println(msg);
		System.out.println(num);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		Class<?> cls=Class.forName("www.bit.java.reflect.Fruit");
		//調用Class類的getMethod()方法取得指定普通方法
		Method method=cls.getMethod("fun1",String.class);
		System.out.println(method);
	}
}

運行結果如下:

public void www.bit.java.reflect.Fruit.fun1(java.lang.String)

但需要注意的是,getMethod()方法只能取得public權限的普通方法,可以自行測試。還有一點是若指定方法在本類中沒有,則會在父類中繼續查找該方法。下面進行演示:

package www.bit.java.reflect;
import java.lang.reflect.Method;
class Fruit{
	public void fun0() {
		System.out.println("子類Apple的父類Fruit的普通方法fun0");
	}
}
class  Apple extends Fruit{
	//public權限的普通方法
	public void fun1(String msg) {
		System.out.println(msg);
	}
	//private權限的普通方法
	private void fun2(int num) {
		System.out.println(num);
	}
	//default權限的普通方法
	void fun3(String msg,int num) {
		System.out.println(msg);
		System.out.println(num);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		//取得子類Apple的Class類對象
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		//調用Class類的getMethod()方法取得指定普通方法fun0
		//注意的是:Apple類中沒有fun0方法
		Method method=cls.getMethod("fun0");
		System.out.println(method);
		//但是打印出的結果表明含有該方法,這是因爲在子類中查找沒有之後繼續在父類中查找的結果!
	}
}

運行結果如下:

public void www.bit.java.reflect.Fruit.fun0()
(2)Class類的getDeclaredMethod()方法

該方法的功能是根據方法名以及參數在本類中取得任意權限的普通方法。

getDeclaredMethod()方法的源代碼如下:

    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

該方法的返回類型爲java.lang.reflect.Method類的對象,第一個參數是字符串,表示指定方法的方法名稱,第二個參數是可變參數,表示指定方法的參數的Class類對象。

調用getDeclaredMethod()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Method;
class Fruit{
	public void fun0() {
		System.out.println("子類Apple的父類Fruit的普通方法fun0");
	}
}
class  Apple extends Fruit{
	//public權限的普通方法
	public void fun1(String msg) {
		System.out.println(msg);
	}
	//private權限的普通方法
	private void fun2(int num) {
		System.out.println(num);
	}
	//default權限的普通方法
	void fun3(String msg,int num) {
		System.out.println(msg);
		System.out.println(num);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		//取得子類Apple的Class類對象
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		//調用Class類的getDeclaredMethod()方法取得任意權限的指定的普通方法
		//取得public權限的普通方法
		Method method1=cls.getDeclaredMethod("fun1",String.class);
		System.out.println(method1);
		//取得private權限的普通方法
		Method method2=cls.getDeclaredMethod("fun2",int.class);
		System.out.println(method2);
		//取得default權限的普通方法
		Method method3=cls.getDeclaredMethod("fun3",String.class,int.class);
		System.out.println(method3);		
	}
}

運行結果如下:

public void www.bit.java.reflect.Apple.fun1(java.lang.String)
private void www.bit.java.reflect.Apple.fun2(int)
void www.bit.java.reflect.Apple.fun3(java.lang.String,int)

需要注意的是:getDeclaredMethod()方法取得指定的任意權限的普通方法並且只在本類中尋找,無關父類。

故,getMethod()方法與getDeclaredMethod()方法的區別在於:

(1)getMethod()方法取得指定的權限爲public的普通方法並且若該指定方法在本類中沒有,會繼續在父類中查找。

(2)getDeclaredMethod()方法取得任意權限的指定普通方法並且只能在本類中查找,不會在父類中查找。

3.2 取得全部普通方法

(1)Class類的getMethods()方法

該方法的功能爲取得本類以及父類中所有權限爲public的普通方法。

getMethods()方法的源代碼如下:

public Method[] getMethods() throws SecurityException

該方法返回的是Method類對象數組。

調用getMethods()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Method;
class Fruit{
	public void fun0() {
		System.out.println("子類Apple的父類Fruit的普通方法fun0");
	}
}
class  Apple extends Fruit{
	//public權限的普通方法
	public void fun1(String msg) {
		System.out.println(msg);
	}
	//private權限的普通方法
	private void fun2(int num) {
		System.out.println(num);
	}
	//default權限的普通方法
	void fun3(String msg,int num) {
		System.out.println(msg);
		System.out.println(num);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		//取得子類Apple的Class類對象
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		//調用Class類的getMethods()方法取得在子類以及父類中所有權限爲public的普通方法 
		Method[] method=cls.getMethods();
		for (Method method1 : method) {
			System.out.println(method1);
		}
	}
}

運行結果如下:

public void www.bit.java.reflect.Apple.fun1(java.lang.String)
public void www.bit.java.reflect.Fruit.fun0()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

在運行結果中會發現不止含有Apple子類以及Fruit父類的權限爲public的普通方法,還含有Object類的方法。這是因爲任何類都默認繼承Object類,所以Object類是任何類的父類,故在調用getMethods()方法時,也取得了Object類的權限爲public的普通方法。

(2)Class類的getDeclaredMethods()方法

該方法的功能爲取得在本類中所有的任意權限的普通方法。

getDeclaredMethods()方法的源代碼如下:

public Method[] getDeclaredMethods() throws SecurityException

該方法的返回類型爲java.lang.reflect.Method類的對象數組。

調用getDeclaredMethods()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Method;
class Fruit{
	public void fun0() {
		System.out.println("子類Apple的父類Fruit的普通方法fun0");
	}
}
class  Apple extends Fruit{
	//public權限的普通方法
	public void fun1(String msg) {
		System.out.println(msg);
	}
	//private權限的普通方法
	private void fun2(int num) {
		System.out.println(num);
	}
	//default權限的普通方法
	void fun3(String msg,int num) {
		System.out.println(msg);
		System.out.println(num);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		//取得子類Apple的Class類對象
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		//調用Class類的getDeclaredMethods()方法取得在本類中的任意權限的所有普通方法 
		Method[] method=cls.getDeclaredMethods();
		for (Method method1 : method) {
			System.out.println(method1);
		}
	}
}

運行結果如下:

public void www.bit.java.reflect.Apple.fun1(java.lang.String)
private void www.bit.java.reflect.Apple.fun2(int)
void www.bit.java.reflect.Apple.fun3(java.lang.String,int)

故,getMethods()方法與getDeclaredMethods()方法的區別在於:

(1)getMethods()方法用於取得本類以及父類中所有權限爲public的普通方法。

(2)getDeclaredMethods()方法用於取得僅在本類中的任意權限的所有普通方法。

3.3 通過反射調用普通方法

既然可以通過以上四種方法拿到具體類中的普通方法,那麼如何調用該它呢?通過反射調用拿到的Method類對象,是利用Method類的invoke()方法。

Method類的invoke()方法的源代碼如下:

public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException

返回類型爲Object類對象,第一個參數爲Object類對象,用於接收需要調用的方法所對應的類的對象,第二個參數是可變參數,用於接收需要調用的方法的參數。

調用invoke()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Method;
class Fruit{
	public void fun0() {
		System.out.println("子類Apple的父類Fruit的普通方法fun0");
	}
}
class  Apple extends Fruit{
	//public權限的普通方法
	public void fun1(String msg) {
		System.out.println(msg);
	}
	//private權限的普通方法
	private void fun2(int num) {
		System.out.println(num);
	}
	//default權限的普通方法
	void fun3(String msg,int num) {
		System.out.println(msg);
		System.out.println(num);
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		//取得子類Apple的Class類對象
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		//調用Class類的getDeclaredMethod()方法取得在本類中的任意權限的指定普通方法 
		//下面測試取得fun1普通方法
		Method method=cls.getDeclaredMethod("fun1",String.class);
		//在調用invoke()方法前,需要先產生具體類的實例化對象,用於傳入invoke()方法的第一個參數中
		Object object=cls.newInstance();
		Object result=method.invoke(object,"通過反射調用普通方法");
		//返回的result對象表示正向操作調用fun1()方法的返回類型void的返回值
		System.out.println(result);
	}
}

運行結果如下:

通過反射調用普通方法
null

在運行結果中,可以看出通過反射正確地調用了想要調用的方法fun1(),並且invoke()方法的返回值是正向調用fun1()方法時的返回值。符合預期,所以說可以通過反射調用普通方法。

但需要注意的是,在調用invoke()方法前需要先實例化具體類的對象,從而可以在invoke()方法中的第一個參數中使用。所以說,一般在具體類中最好定義無參的構造方法,用於方便產生具體類的實例化對象。

4. Field類

Field類是用於描述具體類的屬性的類,類似於Method類以及Constructor類。但需要注意的是類中的所有屬性一定在類對象的實例化後才進行空間分配,所以此時要想要調用類的屬性,必須保證有實例化對象,通過反射調用newInstance()方法可以直接取得實例化對象。這再一次說明在自定義具體類時,定義無參的構造方法的必要性!

4.1 取得指定屬性

(1)Class類的getField()方法

該方法只能取得權限爲public的指定屬性。

getField()方法的源代碼如下:

 public Field getField(String name)

返回類型爲Field類的對象,參數類型是字符串,表示屬性名稱。

調用getField()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Field;
class Fruit{
	//public權限的屬性
	public int m;
	//private權限的屬性
	private int n;
	public void fun0() {
		System.out.println("子類Apple的父類Fruit的普通方法fun0");
	}
}
class  Apple extends Fruit{
	//public權限的屬性
	public String msg;
	//private權限的屬性
	private int num=20;
	//default權限的屬性
	double data=10.11;
	//public權限的普通方法
	public void fun1(String msg) {
		this.msg=msg;
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		//取得子類Apple的Class類對象
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		//調用Class類的getField()方法根據屬性名稱取得public權限的指定屬性
		Field field1=cls.getField("m");
		Field field2=cls.getField("msg");
		System.out.println(field1);
		System.out.println(field2);
	}
}

運行結果如下:

public int www.bit.java.reflect.Fruit.m
public java.lang.String www.bit.java.reflect.Apple.msg

從運行結果可以看出,調用getField()方法取得指定屬性時,當該指定屬性在本類中不存在時,會繼續在其父類中查找。並且需要注意:getField()方法只能取得權限爲public的指定屬性,若不是public權限的屬性而調用getField()方法時,會出現異常。可以自行測試!

(2)Class類的getDeclaredField()方法

該方法用於在本類中取得任意權限的指定屬性。

getDeclaredField()方法的源代碼如下:

public Field getDeclaredField(String name)

調用getDeclaredField()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Field;
class Fruit{
	//public權限的屬性
	public int m;
	//private權限的屬性
	private int n;
	public void fun0() {
		System.out.println("子類Apple的父類Fruit的普通方法fun0");
	}
}
class  Apple extends Fruit{
	//public權限的屬性
	public String msg;
	//private權限的屬性
	private int num=20;
	//default權限的屬性
	double data=10.11;
	//public權限的普通方法
	public void fun1(String msg) {
		this.msg=msg;
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		//取得子類Apple的Class類對象
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		//調用Class類的getDeclaredField()方法根據屬性名稱取得任意權限的指定屬性
		Field field1=cls.getDeclaredField("msg");
		Field field2=cls.getDeclaredField("data");
		Field field3=cls.getDeclaredField("num");
		System.out.println(field1);
		System.out.println(field2);
		System.out.println(field3);
	}
}

運行結果如下:

public java.lang.String www.bit.java.reflect.Apple.msg
double www.bit.java.reflect.Apple.data
private int www.bit.java.reflect.Apple.num

從代碼以及運行結果中可以看出,getDeclaredField()方法可以在本類中取得任意權限的指定屬性。

故,getField()方法與getDeclaredField()方法的區別在於:

(1)getField()方法是在本類以及其父類中查找權限爲public的指定屬性。

(2)getDeclaredField()方法只在本類中查找任意權限的指定屬性。

4.2 取得所有屬性

(1)Class類的getFields()方法

該方法是在本類以及父類中查找權限爲public的所有屬性。

getFields()方法的源代碼如下:

public Field[] getFields() throws SecurityException

返回類型爲java.lang,reflect.Field類的對象數組。

調用getFields()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Field;
class Fruit{
	//public權限的屬性
	public int m;
	//private權限的屬性
	private int n;
	public void fun0() {
		System.out.println("子類Apple的父類Fruit的普通方法fun0");
	}
}
class  Apple extends Fruit{
	//public權限的屬性
	public String msg;
	//private權限的屬性
	private int num=20;
	//default權限的屬性
	double data=10.11;
	//public權限的普通方法
	public void fun1(String msg) {
		this.msg=msg;
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		//取得子類Apple的Class類對象
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		//調用Class類的getFields()方法取得權限爲public的所有屬性
		Field[] field=cls.getFields();
		for (Field field1 : field) {
			System.out.println(field1);
		}
	}
}

運行結果如下:

public java.lang.String www.bit.java.reflect.Apple.msg
public int www.bit.java.reflect.Fruit.m

(2)Class類的getDeclaredFields()方法

該方法功能爲只在本類中查找任意權限的所有屬性。

getDeclaredFields()方法的源代碼如下:

    public Field[] getDeclaredFields() throws SecurityException 

該方法的返回類型爲java.lang.reflect.Field類的對象數組。

調用getDeclaredFields()方法如下:

package www.bit.java.reflect;
import java.lang.reflect.Field;
class Fruit{
	//public權限的屬性
	public int m;
	//private權限的屬性
	private int n;
	public void fun0() {
		System.out.println("子類Apple的父類Fruit的普通方法fun0");
	}
}
class  Apple extends Fruit{
	//public權限的屬性
	public String msg;
	//private權限的屬性
	private int num=20;
	//default權限的屬性
	double data=10.11;
	//public權限的普通方法
	public void fun1(String msg) {
		this.msg=msg;
	}
}
public class Test {
	public static void main(String[] args) throws Exception {
		//取得子類Apple的Class類對象
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		//調用Class類的getDeclaredFields()方法取得任意權限的所有屬性
		Field[] field=cls.getDeclaredFields();
		for (Field field1 : field) {
			System.out.println(field1);
		}
	}
}

運行結果如下:

public java.lang.String www.bit.java.reflect.Apple.msg
private int www.bit.java.reflect.Apple.num
double www.bit.java.reflect.Apple.data

故,getFields()方法與getDeclaredFields()方法的區別在於:

(1)getFields()方法是在本類以及其父類中查找權限爲public的所有屬性。

(2)getDeclaredFields()方法是隻在本類中查找任意權限的所有屬性。

4.3 通過反射設置屬性值以及取得屬性值

(1)通過反射設置屬性值

public void set(Object obj,Object value)

第一個參數表示具體類的實例化對象,可以通過反射調用newInstance()方法實例化對象。

第二個參數表示需要設置的屬性的值。

(2)通過反射取得屬性值

public Object get(Object obj)

返回類型表示取得的屬性的值。

第一個參數接收具體類的實例化對象。

具體操作如下所示:

package www.bit.java.reflect;
import java.lang.reflect.Field;
class  Apple{
	//public權限的屬性
	public String msg;
}
public class Test {
	public static void main(String[] args) throws Exception {
		//取得子類Apple的Class類對象
		Class<?> cls=Class.forName("www.bit.java.reflect.Apple");
		//調用Class類的getDeclaredField()方法取得任意權限的指定屬性
		Field field=cls.getDeclaredField("msg");
		//對具體類實例化對象
		Object object=cls.newInstance();
		//調用set()方法設置屬性值
		field.set(object,"設置屬性值");
		//調用get()方法取得屬性值
		System.out.println(field.get(object));
	}
}

運行結果如下:

設置屬性值
以上就是關於反射的四大類:Class類、Constructor類、Method類、Field類。如有錯誤,望糾正,願改正!













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