1. 程式人生 > >Java之反射四大核心類Class/Constructor/Method/Field

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()[email protected]]
總結:之前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類。如有錯誤,望糾正,願改正!

相關推薦

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

首先什麼是反射?反射指的是物件的反向操作,先通過以下程式碼看看什麼是正向操作。package www.bit.java.reflect; import java.util.Date; public class Test { public static void main(S

深入分析Java反射(一)-核心庫和方法

前提 Java反射的API在JavaSE1.7的時候已經基本完善,但是本文編寫的時候使用的是Oracle JDK11,因為JDK11對於sun包下的原始碼也上傳了,可以直接通過IDE檢視對應的原始碼和進行Debug。 本文主要介紹反射的基本概念以及核心類Class、Constructor、Method、Fie

java基本數據

長整型 浮點型 java組合 float 必須 計算 line style 浮點數 11,java裏面有沒有long double類型或者比double更精度的? =========== 11,java裏面有沒有long double類型或者比double更精度

java反射機制

uid com leg ava pga rim http .com sao java基礎——String存放的區域 一道關於性能方面的難題 談談主席樹的那些事兒 分享一套幾十個源代碼,都是vc++的,打包提供 6h2媒吩讀http://p.baidu.com/ito

JAVA反射方法的應用】

JAVA之反射的應用 import java.util.HashMap; import java.util.Map; public class Child extends Parent { public int add(int a,int b){ return a+b; }

Java靜態內部類(static class)

轉載請註明出處:http://riddickbryant.iteye.com/blog/555545 在一個類中建立另外一個類,叫做成員內部類。這個成員內部類可以靜態的(利用static關鍵字修飾),也可以是非靜態的。由於靜態的內部類在定義、使用的時候會有種種的限制。所以在實際工作中用到

javastatic四大作用總結(轉載)

用於學習記錄,原地址(https://www.cnblogs.com/dotgua/p/6354151.html) 在java的關鍵字中,static和final是兩個我們必須掌握的關鍵字。不同於其他關鍵字,他們都有多種用法,而且在一定環境下使用,可以提高程式的執行效能,優化程式的結構。下面我們

Java路:抽象

抽象類 在Java中可以建立一種類專門用來做父類,這種類稱為“抽象類”。抽象類實際上也是一個類,只是與之前的普通類相比,內部新增了抽象方法。 1、抽象方法 抽象方法是隻宣告而未實現的方法。 例: void f(); // 只有宣告,沒有實現。 2、抽象類的定義與使

Java路:抽象與介面對比

先上圖: 下面詳細說下: 1、相同點 (1)都是抽象型別; (2)都可以有實現方法;抽象類中可以實現普通方法,介面中可以實現預設方法(Java 8)。 (3) 都可以不需要實現類或者繼承者去實現所有方法。(以前不行,現在介面中預設方法不需

Javaeclipse將工具打成Jar包、使用jar包、以及刪除jar包

Eclipse如何匯出jar包??? 選中對應的工具類,右鍵==>Export... ==>選中Java目錄下的JAR File==>Next==>選擇匯出路徑==>Fi

Java反射

       Java的反射機制,常用的4個類,Class、Field、Constractor、Method。Class是一個比較特殊的類,可以說任何一個類都是Class的例項物件。後面的Field、Constractor、Method三個類都是在java.lang.refl

Java路:System對I/O的支援

為了支援標準輸入輸出裝置,Java定義了3個特殊的流物件常量: 錯誤輸出:public static final PrintStream err; 系統輸出:public static final PrintStream out; 系統輸入:public static final Inp

Java路:RandomAccessFile

Java提供了專門處理檔案的類,即RandomAccessFile(隨機訪問檔案)類。該類是Java語言中功能最為豐富的檔案訪問類。 RandomAccessFile類支援“隨機訪問”方式,“隨機”是指可以跳轉到檔案的任意位置處讀寫資料。 在訪問一個檔案的時候,不必把檔

JAVABDB資料庫工具抽象實現

import java.io.File; import com.sleepycat.je.Database; import com.sleepycat.je.DatabaseConfig; import com.sleepycat.je.DatabaseEntry; import com.s

學習筆記Android四大核心元件詳解

概述 Android四大核心元件指的是Activity,Service,ContentProvider,BroadCastReceiver,核心元件都是由Android系統進行管理和維護的,一般都要在清單檔案中進行註冊或者在程式碼中動態註冊。 Activ

Java 的 IO 四大詳解(上)

1、概述      Java 的IO通過java.io 包下的類和介面來支援,java.io包下主要包括輸入、輸出兩種流。每種輸入輸出流又可分為位元組流和字元流兩大類。      位元組流以位元組為單位處理輸入、輸出操作;      字元流以字元來處理輸入

java反射Reflect

1.Class類的使用 (1)java中普通的資料型別類和靜態的成員不屬於物件。 (2)類也是物件,是java.lang.Class類的例項物件。 (3)Class類本身是無法new自身的。因為可以從原始碼看到:          C

JAVA編寫簡單快取

一、問題          這幾天寫webservice提供介面時                  問題:當前臺通過條件呼叫介面查詢資料時,查詢的資料量太大。                   為

java 利用反射例項化物件

package com.zhiru; /* * java 使用反射例項化一個類物件 * 第一種方式:建立類類物件,呼叫類類物件的newInatance方法獲取要例項化的類的物件,然後呼叫物件的s

java利用反射獲取物件名以及物件屬性名

原本想用來做搜尋的時候用,但是沒用上,所以還是貼出來。這個可以用在迴圈判斷物件的時候比較有用,程式碼如下:   rr=new ReceiveResume();   String a=rr.getClass().toString();   String b[]=a.spl