跟我学Java反射——三步曲


    上一篇文章我们通过反射得到运行类的构造函数、对象实例、父类、实现的接口、所在包、以及注解,这篇文章我们将学习通过反射得到运行类的相关属性信息以及相关的方法信息。

  

获取类的完整结构

 

运行类的Field

 

    通过运行类来获取它的相关属性,这一点在开发中用途还是很广泛的,下面我们就来看下跟Field相关的知识。

 

1.获取到运行类中及其父类中声明为public的属性

 

//获取到运行类中及其父类中声明为public的属性
@Test
public void Test1(){
	Class clazz = Person.class;
	
	//1.getFields,只能获取到运行类中及其父类中声明为public的属性
	Field[] fields = clazz.getFields();
	for (int i = 0; i < fields.length; i++) {
		System.out.println(fields[i]);
	}
}

运行结果:

 

    publicjava.lang.String com.tgb.reflect.common.Person.name

    public doublecom.tgb.reflect.common.Creature.weight

 

 

2.获取运行类本身声明的所有属性

 

//获取运行类本身声明的所有属性
@Test
public void test2(){
	Class clazz = Person.class;
	//2.getDeclaredFields,只能获取运行类本身声明的所有属性
	Field[] fields1 = clazz.getDeclaredFields();
	for (int i = 0; i < fields1.length; i++) {
		System.out.println(fields1[i]);
	}
}

运行结果:

 

    private int com.tgb.reflect.common.Person.age

    public java.lang.String com.tgb.reflect.common.Person.name

    int com.tgb.reflect.common.Person.id

 

 

    我们发现用不同权限修饰符修饰的属性,我们想通过反射来获取时也是需要用不同的方法的,类的getFields()只能获取到运行类中及其父类中声明为public的属性,而类的getDeclaredFields()只能获取运行类本身声明的所有属性。

 

    有时候我们只是获取整个属性还是不够的,我们还需要获取属性字段是权限修饰符、变量类型、属性名字。

 

3.获取属性的权限修饰符和数据类型和属性名字

 

	/**
	 * 获取属性的权限修饰符和数据类型和属性名字
	 */
	@Test
	public void Test3(){
		Class clazz = Person.class;
		Field[] fields1 = clazz.getDeclaredFields();
		for (Field f:fields1) {
			//获取属性权限修饰符
			int i=f.getModifiers();
			String str1=Modifier.toString(i);
			System.out.print("权限修饰符是:"+str1+" ");
			
			//获取属性的变量类型
			Class type = f.getType();
			System.out.print("变量类型是:"+type.getName()+" ");
			
			//获取属性名字
			System.out.println("属性名字是:"+f.getName());
		}
	}

运行结果:

 

    权限修饰符是:private变量类型是:int 属性名字是:age

    权限修饰符是:public变量类型是:java.lang.String 属性名字是:name

    权限修饰符是: 变量类型是:int属性名字是:id

 

    这样我们通过字段的getModifiers()方法可以获取变量的权限修饰符、字段的getType()得到属性变量类型、type.getName()获取属性名字。

 

 

运行类的Method

 

1.获取运行类及其父类中的所有声明为public的方法

 

//获取运行类及其父类中的所有声明为public的方法
@Test
public void test1() {
	Class clazz = Person.class;

	// 1. getMethods 获取运行类及其父类中的所有声明为public的方法
	Method[] m1 = clazz.getMethods();
	for (Method m : m1) {
		// String name=m.getName();
		System.out.println(m);
	}
}

运行结果:

    publicjava.lang.String com.tgb.reflect.common.Person.toString()

    public int com.tgb.reflect.common.Person.compareTo(java.lang.Integer)

    public int com.tgb.reflect.common.Person.compareTo(java.lang.Object)

    public java.lang.String com.tgb.reflect.common.Person.getName()

    public void com.tgb.reflect.common.Person.setName(java.lang.String)

    public static void com.tgb.reflect.common.Person.info()

    public void com.tgb.reflect.common.Person.show()

    public int com.tgb.reflect.common.Person.getAge()

    public void com.tgb.reflect.common.Person.setAge(int)

    public void com.tgb.reflect.common.Creature.breath()

    public final void java.lang.Object.wait() throws java.lang.InterruptedException

    public final void java.lang.Object.wait(long,int) throws   java.lang.Interrupted Exception

    public final native void java.lang.Object.wait(long) throws       java.lang.Interrupted Exception

    public boolean java.lang.Object.equals(java.lang.Object)

    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()

 

 

2.获取运行时类本身声明的所有的方法

 

//获取运行时类本身声明的所有的方法
@Test
public void test2() {
	Class clazz = Person.class;
	
	// 2. getDeclaredMethods获取运行时类本身声明的所有的方法
	Method[] m2 = clazz.getDeclaredMethods();
	for (Method m : m2) {
		System.out.println(m);
	}
}

运行结果 :


    public java.lang.String com.tgb.reflect.common.Person.toString()

    public int com.tgb.reflect.common.Person.compareTo(java.lang.Integer)

    public int com.tgb.reflect.common.Person.compareTo(java.lang.Object)

    public java.lang.String com.tgb.reflect.common.Person.getName()

    public void com.tgb.reflect.common.Person.setName(java.lang.String)

    public static voidcom.tgb.reflect.common.Person.info()

    public void com.tgb.reflect.common.Person.show()

    private void com.tgb.reflect.common.Person.display(java.lang.String)

    public int com.tgb.reflect.common.Person.getAge()

    public void com.tgb.reflect.common.Person.setAge(int)

 

    通过class类的getMethods()方法可以得到运行类本身的所有public方法及其父类中的所有声明为public的方法;通过class类的getDeclaredMethods()可以得到运行类本身的所有方法。

 

3.获取方法的权限修饰符、返回值类型、方法名、形参列表、注解、异常


	// 权限修饰符、返回值类型、方法名、形参列表、注解、异常
	@Test
	public void Test3() {
		Class clazz = Person.class;
		Method[] m2 = clazz.getDeclaredMethods();
		for (Method m : m2) {
		
			//打印下方法
			System.out.print("方法是:"+m);
			
			// 1.权限修饰符
			String str1 = Modifier.toString(m.getModifiers());
			System.out.print(" 权限修饰符是:" + str1);

			// 2.返回值类型
			Class class1 = m.getReturnType();
			System.out.print("  返回值类型是:" + class1.getName());

			// 3.方法名
			System.out.print("  方法名是:" + m.getName());

			// 4.形参列表
			Class[] paras = m.getParameterTypes();
			if (paras.length != 0) {
				for (int i = 0; i < paras.length; i++) {
					System.out.print(" 形参是:" + paras[i].getName()+" args"+i+" ");
				}
			}
			
			
			// 5.注解
			Annotation[] annotations = m.getAnnotations();
			if (annotations.length!=0) {
				for (Annotation ans : annotations) {
					System.out.print(" 注解是:" + ans);
				}
			}
			
			// 6.异常类型
			Class[] exps= m.getExceptionTypes();
			if (exps.length!=0) {
				for (int i = 0; i < exps.length; i++) {
					System.out.print(" 异常类型"+exps[i].getName());
				}
			}
			
			
			System.out.println();
			System.out.println();
		}
	}

运行结果:

 

    方法是:publicjava.lang.String com.tgb.reflect.common.Person.toString() 权限修饰符是:public  返回值类型是:java.lang.String  方法名是:toString

 

    方法是:public intcom.tgb.reflect.common.Person.compareTo(java.lang.Integer) 权限修饰符是:public  返回值类型是:int 方法名是:compareTo 形参是:java.lang.Integer args0

 

    方法是:public intcom.tgb.reflect.common.Person.compareTo(java.lang.Object) 权限修饰符是:publicvolatile  返回值类型是:int  方法名是:compareTo 形参是:java.lang.Object args0

 

    方法是:publicjava.lang.String com.tgb.reflect.common.Person.getName() 权限修饰符是:public  返回值类型是:java.lang.String  方法名是:getName

 

    方法是:public voidcom.tgb.reflect.common.Person.setName(java.lang.String) 权限修饰符是:public  返回值类型是:void 方法名是:setName 形参是:java.lang.String args0

 

方法是:public staticvoid com.tgb.reflect.common.Person.info() 权限修饰符是:public static  返回值类型是:void 方法名是:info

 

    方法是:public voidcom.tgb.reflect.common.Person.show() 权限修饰符是:public  返回值类型是:void 方法名是:show 注解是:@com.tgb.reflect.common.MyAnnotation(value=abc123)

 

    方法是:private voidcom.tgb.reflect.common.Person.display(java.lang.String) throwsjava.io.IOException 权限修饰符是:private 返回值类型是:void  方法名是:display形参是:java.lang.String args0 异常类型java.io.IOException

 

    方法是:public intcom.tgb.reflect.common.Person.getAge() 权限修饰符是:public  返回值类型是:int 方法名是:getAge

 

    方法是:public voidcom.tgb.reflect.common.Person.setAge(int) 权限修饰符是:public 返回值类型是:void 方法名是:setAge 形参是:int args0

 

    通过这个方法我们可以通过反射得到运行类方法的权限修饰符、返回值类型、方法名、形参列表、注解、异常,这些功能还是比较常用的。

 

    获取类的属性方法也介绍完了,到这来关于利用反射得到运行类的完整类结构都介绍完毕了,下面我们来接着学习在反射中用的比较多的,通过反射调用类中指定属性和指定方法的例子。

 

 

通过反射调用类中的指定方法、指定属性

 

通过反射调用类中的指定属性

 

    类中变量的声明有几种,分别是privatepublic和默认、static,这几种权限修饰符修饰的变量,如果我们想通过反射来调用,那么应该怎么调用呢。

 

1.调用运行类中public修饰的指定的属性

 

// 调用运行类中由public修饰的指定的属性  public String name;
@Test
public void test4() throws Exception {
	// 通过反射获取person类的对象实例
	Class class1 = Person.class;
    //获取运行类的空参构造函数  
    Constructor constructor = class1.getConstructor();  
    //创建对应的运行类对象时,使用newInstance,实际上就是调用了运行时类的空参的构造器;  
    Person person = (Person)constructor.newInstance(); 
	//获取name属性
	Field fieldName = class1.getField("name");
	//给name属性赋值
	fieldName.set(person, "jack");
	System.out.println("name:"+person.getName());
}

运行结果:

 

    我是Person的父类Creature<T,N>类的空参构造函数

    我是Person类的public修饰的空参构造函数Person()

    name:jack

 

2.调用运行类中private修饰的指定的属性

 

//调用运行类中private修饰的指定的属性 private int age;
@Test
public void test5()throws Exception{
	// 通过反射获取person类的对象实例
	Class class1 = Person.class;
    //获取运行类的空参构造函数  
    Constructor constructor = class1.getConstructor();  
    //创建对应的运行类对象时,使用newInstance,实际上就是调用了运行时类的空参的构造器;  
    Person person = (Person)constructor.newInstance(); 

    //得到private修饰的age变量
    Field fieldAge =class1.getDeclaredField("age");
    //设置允许操作的权限
    fieldAge.setAccessible(true);
    fieldAge.set(person, 20);
    System.out.println("age:"+person.getAge());
}

运行结果:

 

    我是Person的父类Creature<T,N>类的空参构造函数

    我是Person类的public修饰的空参构造函数Person()

    age:20

 

 

3.调用运行类中默认的指定的属性

 

 

//调用运行类中默认的指定的属性   int id;
@Test
public void test6() throws Exception{
	// 通过反射获取person类的对象实例
	Class class1 = Person.class;
    //获取运行类的空参构造函数  
    Constructor constructor = class1.getConstructor();  
    //创建对应的运行类对象时,使用newInstance,实际上就是调用了运行时类的空参的构造器;  
    Person person = (Person)constructor.newInstance(); 

    //获取id属性
	Field fieldId = class1.getDeclaredField("id");
	  //设置允许操作的权限
	fieldId.setAccessible(true);
	//给id属性赋值
	fieldId.set(person, 20);
	System.out.println("id:"+person.getId());

}

运行结果:

 

    我是Person的父类Creature<T,N>类的空参构造函数

    我是Person类的public修饰的空参构造函数Person()

    id:20

 

4.调用运行类中static修饰的指定的属性

 

//调用运行类中static修饰的指定的属性 private static String desc;;
	@Test
	public void test7() throws Exception{
		// 通过反射获取person类的对象实例
		Class class1 = Person.class;
	    //获取运行类的空参构造函数  
	    Constructor constructor = class1.getConstructor();  
	    //创建对应的运行类对象时,使用newInstance,实际上就是调用了运行时类的空参的构造器;  
	    Person person = (Person)constructor.newInstance(); 
	
	    //获取id属性
		Field fieldDesc = class1.getDeclaredField("desc");
		  //设置允许操作的权限
		fieldDesc.setAccessible(true);//static有无均可
		//给id属性赋值
		fieldDesc.set(person, "描述");
		System.out.println("desc:"+person.getDesc());

	}


运行结果:

 

    我是Person的父类Creature<T,N>类的空参构造函数

    我是Person类的public修饰的空参构造函数Person()

    desc:描述

 

    通过以上对publicprivate、默认、static修饰的属性的调用,我们发现运行结果都会打印运行类Person和父类Creature的空参构造函数呢,这是因为生成Person类的实例对象时调用的是Person类的空参构造函数,而空参构造函数是由类的getConstructor()方法得到的,这个方法会默认得到运行类和父类的构造函数,所有实例化时会一起执行。

 

    通过代码我们发现,只有public修饰的属性和其它的不一样,其它的像private、默认、static修饰的属性使用是一样的,权限修饰符不是public的,得到Field字段必须用类的getDeclaredField()方法,否则取不到属性,并且调用前必须给赋予权限,也就是Field字段的setAccessible(true)方法,这样的话才可以完成调用。

 

 

通过反射调用类中的指定方法

 

1.通过反射调用类中public修饰的指定方法

 

//通过反射调用类中public修饰的指定方法
@Test
public void test4() throws Exception{
	// 通过反射获取person类的对象实例
	Class class1 = Person.class;
    //创建对应的运行类对象时,使用newInstance,实际上就是调用了运行时类的空参的构造器;  
    Person person = (Person)class1.newInstance(); 

    //利用method方法调用
	Method method= class1.getMethod("toString");
	System.out.println("方法是:"+method);
	
	//方法执行返回值
	Object returnValue=method.invoke(person);
	System.out.println("返回值是:"+returnValue);
}

运行结果:

 

    我是Person的父类Creature<T,N>类的空参构造函数

    我是Person类的public修饰的空参构造函数Person()

    方法是:publicjava.lang.String com.tgb.reflect.common.Person.toString()

    我是Person类的public修饰的空参方法toString()

    返回值是:Person[name=null, age=0]

 

 

2.通过反射调用类中非public修饰的带参数的指定方法

 

//通过反射调用类中非public修饰的带参数的指定方法
@Test
public void test5() throws Exception{
	// 通过反射获取person类的对象实例
	Class class1 = Person.class;
    //创建对应的运行类对象时,使用newInstance,实际上就是调用了运行时类的空参的构造器;  
    Person person = (Person)class1.newInstance(); 

    //利用method方法调用
	Method method= class1.getDeclaredMethod("display",String.class);
	System.out.println("方法是:"+method);
	
	//方法执行返回值
	method.setAccessible(true);
	method.invoke(person,"china");
}

运行结果:

 

    我是Person的父类Creature<T,N>类的空参构造函数

    我是Person类的public修饰的空参构造函数Person()

    方法是:private voidcom.tgb.reflect.common.Person.display(java.lang.String)   throwsjava.io.IOException

    我是Person类的public修饰的带注解的display()有参方法,参数是:china

 

 

3.通过反射调用类中static修饰的不带参数的指定方法

 

//通过反射调用类中static修饰的不带参数的指定方法
@Test
public void test6() throws Exception{
	// 通过反射获取person类的对象实例
	Class class1 = Person.class;
    //创建对应的运行类对象时,使用newInstance,实际上就是调用了运行时类的空参的构造器;  
    Person person = (Person)class1.newInstance(); 

    //利用method方法调用
	Method method= class1.getDeclaredMethod("info");
	System.out.println("方法是:"+method);
	
	//方法执行返回值
	method.setAccessible(true);//有无皆可
	method.invoke(person);
}

运行结果:

 

    我是Person的父类Creature<T,N>类的空参构造函数

    我是Person类的public修饰的空参构造函数Person()

    方法是:private staticvoid com.tgb.reflect.common.Person.info()

    我是Person类的public修饰的static的info()空参静态方法

 

    通过反射调用运行类中不同修饰符修饰的方法,跟调用指定的属性的方法差不多,public修饰的用类的getMethod()方法获得指定方法,非public修饰的用类的getDeclaredMethod()方法获取指定方法,调用时需要给予权限用method.setAccessible(true)即可,static方法权限不赋予也可以使用。

 

后记

 

    这篇文章学习了通过反射得到运行类的相关属性、方法信息,重点是如何通过反射调用运行类中的指定方法和属性,关于不同的权限修饰符,调用也不一样,关于反射的基本知识,就介绍到这里,下篇文章讲解一个反射的典型应用动态代理。

猜你喜欢

转载自blog.csdn.net/zwk626542417/article/details/46289341