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类。如有错误,望纠正,愿改正!













猜你喜欢

转载自blog.csdn.net/tongxuexie/article/details/80288791