【java】反射的概念及使用

(一)何为反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
(二)反射的内部作用机制
通过类加载器将class文件加载到JVM中,构造成class对象,我们通过一些方法获得class对象,然后对class对象进行各种方法的调用能够获得目标类的各种信息,比如目标类的对象和方法等。
(三)获得class对象的三种方法
1.Objict中的方法getClass()方法,返回调用者的class对象
Student stu =new Student();//对象都有了还要反射干什么?
Class stuClass=stu.getClass();
2.任何的数据类型都有一个静态的class属性,返回调用者的class对象
Class stuClass=Student.class;//需要导入调用者的包,麻烦
3.Class类的静态方法fromName(String className),返回目标类的class对象
Class stuClass=Class.fromName("包名.Student");//最常用的方法
注意:在运行期间,一个类只会一个Class对象产生,因此上面三种方法产生的class对象都是同一个。
(四)反射的使用
1.通过反射获取构造方法并使用
  • Constructor类:代表类的构造方法。
Class stuClass= Class.forName("包名.Student");  //获得Class对象  
Constructor[] con1=stuClass.getConstructors();//获得全部公有的构造方法
Constructor[] con2=stuClass.getDeclaredConstructors();//获得所有的构造方法
Constructor con3 = stuClass.getConstructor(参数1.class,参数2.class...);//获取一个参数列表相同的公有构造方法
Constructor con4 =stuClass.getDeclaredConstructor((参数1.class,参数2.class...)//获取一个参数列表相同的构造方法
con3.setAccessible(true);//暴力访问获得的构造方法(忽略掉访问修饰符)
Student stu=(Student)con3.newInstance();//反射获得Student对象
2.通过反射获取成员变量并调用
  • Field类:代表类的成员变量
Class stuClass= Class.forName("包名.Student");  //获得Class对象  
Field[] field1= stuClass.getFields();//获取全部公有的成员变量
Field[] field2=stuClass.getDeclaredFields();//获取全部的成员变量
Field field3 = stuClass.getField("成员变量名");//获取指定的公有成员变量
Field field4 = stuClass.getDeclaredField("成员变量名");//获取指定的私有成员变量
Object obj = stuClass.getConstructor().newInstance();//获得Student对象
f3.set(obj, "刘德华");//为Student对象中的name属性赋值
3.通过反射获取成员方法并调用
  • Method类:代表类的方法
Class stuClass= Class.forName("包名.Student");  //获得Class对象 
Method[] m1= stuClass.getMethods();//获得全部公有的成员方法
Method[] m2 = stuClass.getDeclaredMethods();//获得所有的成员方法
Method m3 = stuClass.getMethod("方法名", 参数.class,参数.class,...);//获得指定的公有成员方法
Method m4 = stuClass.getDeclaredMethod("方法名", 参数.class,参数.class,...);//获得指定的私有成员方法
Object obj = stuClass.getConstructor().newInstance();//获得Student对象
m4.setAccessible(true);//解除私有限定
m4.invoke(obj, 参数,参数,...);//调用指定的成员方法
4.通过反射运行配置文件内容
public class Test {
	public static void main(String[] args) throws Exception {
		//Properties类用于读取配置文件的键值对
		Properties p=new Properties();
		FileReader fr=new FileReader("class.txt");
		p.load(fr);
		//通过键获得值
		String className=p.getProperty("className");
		String methodName=p.getProperty("methodName");
		//创建字节码文件对象,获得无参构造方法对象
		Class clazz=Class.forName(className);
		Constructor con=clazz.getConstructor();
		//通过构造方法获得实例对象
		Object obj=con.newInstance();
		//获得成员方法对象
		Method met=clazz.getDeclaredMethod(methodName);
		//调用方法
		met.invoke(obj,参数,参数,...);		
	}
}
5.通过反射越过泛型检查

泛型只作用在编译期,编译过后的class文件不含泛型,即泛型擦除,因此可以通过反射越过泛型检查,举个栗子:

public class ReflectTest {

	public static void main(String[] args) throws Exception {
		ArrayList<Integer> list = new ArrayList<Integer>();
		//添加元素到集合
		list.add(new Integer(30));
		list.add(new Integer("12345"));
		list.add(123);
		//list.add("哈哈");因为有泛型类型的
         	System.out.println(list);
		
		//通过反射技术,实现添加任意类型的元素
		//获取字节码文件对象
		Class c = Class.forName("java.util.ArrayList");
		
		//2, 找到add方法
		Method addMethod = c.getMethod("add", Object.class);
		
		//3,  执行add()方法
		addMethod.invoke(list, "哈哈");// list.add("哈哈");
		System.out.println(list);
	}
}

其实泛型擦除并没有什么实际价值,只是为了让我们更了解通过反射获得类的方法运行而已。


反射的总结就先写到这里啦~等以后有新的认识的时候再来填填补补。
发布了19 篇原创文章 · 获赞 51 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_42370146/article/details/96857544