详述反射中构造方法、属性和普通方法

本文深入解析Java反射机制,涵盖构造方法、普通方法和属性的获取、信息读取及使用方式。通过实例演示如何利用反射创建对象、调用方法及操作属性。

一.构造方法

1.获取某个类中声明的构造方法实例对象

先创建这样一个Student类,里面含有两个构造方法,一个属性,一个普通方法:

package venus;

public class Student {

	public String name;
	
	public Student() {
		
	}
	
	public Student(String name) {
		this.name=name;
	}
	
	public void doHomeWork() {
		System.out.println(name+"正在做作业");
	}
}

以下是第一种获取构造方法的方式:

第9行:获取一个Student类对应的class对象。

第10行:调用getConstructor方法获取clazz变量中Student类中的构造方法。Constructor是用来存储构造方法的类

第12行:在getConstructor方法的参数列表中加入Student类中第二个构造方法的参数列表,则得到的就是Student类中的第二个构造方法。

该方法的特点就是只能获取public修饰符修饰的构造方法。

package venus;

import java.lang.reflect.Constructor;

public class Test {

	public static void main(String[] args) {
		try {
			Class clazz=Student.class;
			Constructor constructor = clazz.getConstructor();
			System.out.println(constructor.getName());
			constructor=clazz.getConstructor(String.class);
			System.out.println(constructor.getName());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

那么如果想获取非public修饰的构造方法,就要使用下面的方式:

package venus;

import java.lang.reflect.Constructor;

public class Test {

	public static void main(String[] args) {
		try {
			Class clazz=Student.class;
			Constructor constructor=clazz.getDeclaredConstructor();
			System.out.println(constructor.getName());
			constructor=clazz.getDeclaredConstructor(String.class);
			System.out.println(constructor.getName());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

和上一种方式的区别就是这种方式使用的getDeclaredConstructor方法,它的特点就是无视访问修饰权限。 

2.获取该构造方法的信息

以下是获取构造方法信息的代码:

第12行,用constructor对象调用getDeclaringClass方法查看该构造方法的类名。

第15,、16行,用来获取构造方法的修饰符,先调用getModifiers方法获取一个int类型的返回值,然后再用Modifier类对象调用toString方法将该值转为String类型,得到的就是我们要查看的修饰符了。

第19行,getName方法用来查看构造方法的方法名。

第21行,getParameterTypes方法用来获取该构造方法的参数列表,但一个构造方法的参数列表可以有多个数据类型不同的参数,,所以返回值为一个Class类型的数组。

第22、23、24行,对getParameterTypes方法得到的Class类型的数组进行遍历,便可得到class类对象的参数列表了。

package venus;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class Test {

	public static void main(String[] args) {
		Class clazz=Student.class;
		try {
			Constructor constructor = clazz.getDeclaredConstructor(String.class);
			clazz=constructor.getDeclaringClass();
			System.out.println(clazz.getName());
			
			int mod=constructor.getModifiers();
			String result=Modifier.toString(mod);
			System.out.println(result);
			
			System.out.println(constructor.getName());
			
			Class [] str=constructor.getParameterTypes();
			for(Class classs:str) {
				System.out.println(classs.getName());
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}

以下是输出结果:

 

3.使用该构造方法

对构造方法的使用,无非就是创建该类的对象,以下是使用构造方法的代码:

第12行,用该构造方法调用newinstance创建Student类对象,并返回一个Object类的上转型对象。

第13行,因为object为上转型对象,所以要调用Student类新增的方法时要将该对象下转型。

第14行,下转型后即可调用Student类新增的doHomeWork方法。

package venus;

import java.lang.reflect.Constructor;

public class Test {

	public static void main(String[] args) {
		Class clazz=Student.class;
		try {
			Constructor constructor = clazz.getDeclaredConstructor(String.class);
			constructor.setAccessible(true);
			Object object = constructor.newInstance("Tom");
			Student stu=(Student)object;
			stu.doHomeWork();
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}

我们可以看到在第11行有一个setAccessible方法,该方法的作用就是,如果要调用的目标方法为private访问权限的,这时按常理来说是不可以在其他类中使用的,但是该setAccessible方法如果传入的boolean型参数为true,则可以无视方法的访问权限来调用。

二.普通方法

1.获取某个类中声明的普通方法实例对象

和构造方法一样,获取普通方法的实例对象的方式也是分为public修饰和无视访问权限的

①第一种获取的方式只能获取public修饰的普通方法,但是不仅限于本类中的方法,还可以获取继承自父类的普通方法:

第8行,创建Student类的class类对象

第9行,用Student类的class类对象调用getMethods方法获取类中的方法,但getMethods方法获取的是类中及继承自父类的的全部方法,所以返回值是一个Method类型的数组。

第10行,对数组进行遍历,将方法打印出来。

package venus;

import java.lang.reflect.Method;

public class Test {

	public static void main(String[] args) {
		Class clazz=Student.class;
		Method [] methods = clazz.getMethods();
		for(Method method:methods) {
			System.out.println(method.getName());
		}
	}
}

输出结果如下:

 

②第一种方式将类中及继承自父类的所有方法全部打印了出来,但是如果使用getMethod方法,传入目标方法的方法名和参数列表(没有参数列表可以省略第二个参数),便可实现精准查找目标方法:

package venus;

import java.lang.reflect.Method;

public class Test {

	public static void main(String[] args) {
		Class clazz=Student.class;
		try {
			Method method=clazz.getMethod("doHomeWork");
			System.out.println(method.getName());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 这时输出结果为精准的doHomeWork:

③第三种方式就是使用getDeclaredMethods方法,可以无视访问权限,但是只能得到在本类中声明的方法,代码如下:

package venus;

import java.lang.reflect.Method;

public class Test {

	public static void main(String[] args) {
		Class clazz=Student.class;
		try {
			Method [] methods=clazz.getDeclaredMethods();
			for(Method method:methods) {
				System.out.println(method.getName());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

即使是打印全部方法,但是输出结果只有一个doHomeWork方法,说明不能获取继承自父类的方法:

 

2.获取该普通方法的信息

为了更好的获取方法的信息,先将Student类修改为下面的代码:

package venus;

public class Student {

	public String name;
	
	public Student() {
		
	}
	
	public Student(String name) {
		this.name=name;
	}
	
	public static int doHomeWork(int a,String [] scores) {
		System.out.println("正在做作业");
		return 1;
	}
}

 以下是获取普通方法信息的代码:

第13行,打印该普通方法所在的类。

第15行,和构造方法的原理一样,打印方法的修饰符(包括static)。

第17行,得到该方法的返回值。

第20行,打印该方法的方法名。

package venus;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Test {

	public static void main(String[] args) {
		Class clazz=Student.class;
		try {
			Method method=clazz.getMethod("doHomeWork");
			
			System.out.println(clazz.getDeclaringClass());
			
			System.out.println(Modifier.toString(method.getModifiers()));
			
			clazz=method.getReturnType();
			System.out.println(clazz.getName());
			
			System.out.println(method.getName());
			
			Class [] clazzs = method.getParameterTypes();
			for(Class zz:clazzs) {
				System.out.println(zz.getName());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

该程序运行结果如下:

 

3.使用该普通方法

使用构造方法调用的是newinstance,使用普通方法调用的是invoke方法,返回值依然是Object类型的上转型对象,该方法的第一个参数是调用该方法的对象,后面的是一个动态参数,传入的是调用目标方法时传入的参数,代码如下: 

package venus;

import java.lang.reflect.Method;

public class Test {

	public static void main(String[] args) {
		Class clazz=Student.class;
		try {
			Method method=clazz.getMethod("doHomeWork",Integer.TYPE,String [].class);
			method.setAccessible(true);
			Object object=method.invoke(new Student(),1,new String[] {} );
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

要注意的是,无论目标方法是否是静态的,都必须创建对象来调用。 

三.属性

1.获取某个类中声明的属性实例对象

属性的获取和普通方法的获取极为相似,只是使用的方法名发生了一些小小的改变,将Method改为了Field。

①第一种获取方式如下,使用范围与普通方法一样,只能获取public修饰的属性,但是可以获取继承自父类的属性。

package venus;

import java.lang.reflect.Field;

public class Test {

	public static void main(String[] args) {
		Class clazz=Student.class;
		try {
			Field field=clazz.getField("name");
			System.out.println(field.getName());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

②第二种获取方式如下,可以无视访问权限获取属性,但是不能获取继承自父类的属性。

package venus;

import java.lang.reflect.Field;

public class Test {

	public static void main(String[] args) {
		Class clazz=Student.class;
		try {
			Field field=clazz.getDeclaredField("name");
			System.out.println(field.getName());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

2.获取该属性的信息

第11行,获取Student类中的name属性。

第12行,调用getDeclaringClass方法获取该属性所属的类。

第13行,和上面的用法一样,获取该属性的修饰符。

第14行,调用getType方法获取该属性的数据类型。

第15行,调用getName方法获取该属性的名字。

package venus;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Test {

	public static void main(String[] args) {
		Class clazz=Student.class;
		try {
			Field field=clazz.getField("name");
			System.out.println(field.getDeclaringClass());
			System.out.println(Modifier.toString(field.getModifiers()));
			System.out.println(field.getType());
			System.out.println(field.getName());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

输出结果如下:

 

3.使用该属性

对属性的操作有两种,一是获取值,二是设置值,分别使用的方法时get和set。

第12行,调用set方法为该属性设置值,传入的第一个参数是一个Student类型对象,第二个参数是为该属性设置的值。

第13行,调用get方法获取该属性的值,传入的参数还是一个Student类型对象,返回值是一个Object类型的上转型对象

package venus;

import java.lang.reflect.Field;

public class Test {

	public static void main(String[] args) {
		Class clazz=Student.class;
		try {
			Field field=clazz.getField("name");
			field.setAccessible(true);
			field.set(new Student(),"Jim");
			Object obj=field.get(new Student());
			System.out.println(obj);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

要注意的是,无论目标属性是否是静态的,都必须创建对象来调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值