java中的反射

反射概述

1、java反射:在程序运行过程中,可以对任意一个类型进行任意的操作。例如:加载任意类型、调用类型的任意方法、获取任意的成员变量、构造方法,可以创建该类型的对象。
2、对于任意一个对象,都能调用这个对象的任意一个方法【不知道要使用什么类型】
3、如果要获取一个类型的各种内容,首先要获取这个类的字节码对象
4、解剖这个类型,获取类中的成员,需要使用Class类型中定义的方法
5、这种【动态】获取信息以及【动态】访问成员的这种方式,称为:反射

获取类的字节码对象(Class类型对象)的三种方式

1、要想获取和操作类中的内容,首先要获取类的字节码对象
2、这些对象(类的字节码对象,也称为.class对象),都是Class类型的对象
3、获取字节码对象的方式:
1、对象名.getClass():返回的是某个引用指向的具体对象所属的运行是类,的字节码对象。获取到的是那个真正用来创建对象的子类的字节码对象。
2、类名.class:如果已经有了类名,可以通过.class的方式获取这个类的字节码对象。
3、通过Class.forName(String className):Class类中的一个静态方法,可以根据一个类的全类名,动态的加载某个类型。传入一个类的全类名,将类名描述的字节码文件,加载到内存中,形成一个字节码对象,并且把这个对象作为该方法的返回值。(在调用方法之前,是内存中没有这个字节码对象的)。字符串的来源非常广泛,来源于代码,可以来源于键盘录入、网络传输、文件读取、数据库

public class Demo01_获取字节码对象的三种方式 {
	public static void main(String[] args) throws ClassNotFoundException {
		Person p = new Person("zhangsan", 23);
		//getClass的方法获取Person类型的字节码对象
		Class c1 = p.getClass();
		System.out.println(c1);
		
		//类名.class的方式获取Person的字节码对象
		Class c2 = Person.class;
		System.out.println(c2);
		
		//比较两个引用是否指向了同一个对象
		System.out.println(c1 == c2);
		
		//Class的静态forName方法获取字节码对象
		Class c3 = Class.forName("com.obcy.demos.Person");
		System.out.println(c3);
		System.out.println(c2 == c3);
	}
}

Class类型的理解

1、Class类型的实例表示正在运行的java应用程序的类或者接口
2、举例:
(张三, 23),(李四, 24),姓名和年龄都不相同,但是都有年龄和姓名的描述,因此将姓名和年龄抽取到一个类型中,就形成了Person类型,的概念
(yellow,4),(white,2),颜色和腿的个数各不相同,但是都有颜色和腿个数的描述,因此将颜色和腿个数的描述抽取到一个类型中,就形成了Animal类型,的概念
(姓名, 年龄),(颜色, 腿个数),成员变量和成员方法各不相同,但是都有成员变量和成员方法的描述,因此将成员变量和成员方法抽取到一个类型中,就形成Class类型,的概念

3、反射的举例:
房屋设计图纸---->实体房屋,反射:有了房屋,获取设计图纸
汽车设计图纸---->实体汽车,反射:有了汽车,获取设计图纸
无论是房屋设计图纸,还是汽车的设计图纸,都是图纸:抽取一个图纸类型

**

Class类和Class类中的方法

**
class类概述
1、一旦获取了类的字节码对象,就可以使用这个对象的所有方法,这些方法都定义在Class类型中。
2、成员方法:获取这个类的各种信息
成员变量、成员方法、构造方法、内部类、类的注解、类所在的包、类的修饰符、判断类的类型
以上内容获取出来以后,又是一些对象,有专门的数据类型,描述这些对象
3、其中,有一个非常常用的方法:newInstance()
创建这个字节码描述的类型的实例对象,例如使用Person.class字节码对象,调用newInstance方法,就可以创建一个真正的Person对象

public class Demo02_Class类型中的方法 {

	public static void main(String[] args) throws Exception  {
		//获取Person的字节码对象
		Class clazz = Class.forName("com.obcy.demos.Person");
		//创建该类型的实例对象
		Object obj = clazz.newInstance();
		Person p = (Person)obj;
		System.out.println(obj);
		System.out.println(p.getName() + "..." + p.getAge());
	}
}```

**获取类中的构造方法并使用**

	1、通过Class类中的:
 	getConstructor(Class...paramTypes)
 	参数列表:Class...paramTypes,表示一个可变参数,需要传入构造方法的类型的字节码
 	返回值类型:Constructor,表示一个构造方法类型的对象
	2、Constructor类型:
 		1、表示构造方法类型,这个类的每个对象,都是一个确定的,具体的构造方法
 		2、构造方法对象应该具有的功能:获取构造方法各种信息(构造方法修饰符、构造方法名称、构造方法的参数列表、构造方法的注解),最基本的一个功能就是,创建对象
 	 		newInstance(Object...objs)
 	 		返回一个Object类型的对象
 	 		

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Demo05_获取类的构造方法并使用 {

	public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Class c = Person.class;
		//获取c中的构造方法
		Constructor con = c.getConstructor(String.class, int.class);
		//使用这个构造方法,创建有参数的Person对象
		Object obj = con.newInstance("zhangsan", 23);
		System.out.println(obj);
	}
}

获取类中的成员变量并使用
1、通过Class类中的:
getField(String propertyName)
参数列表:属性的名称
返回值类型:Field,表示一个成员变量对象,所属的类型
2、Field类型:表示一个成员变量类型,每个对象都是一个具体的成员变量
作用:获取成员变量的各种信息(修饰符、注解、名称);做各种数据类型的转换
赋值:set(Object obj, Object value),用于给obj对象的,该成员变量,赋value值

import java.lang.reflect.Field;

public class Demo06_获取类的成员变量并赋值 {

	public static void main(String[] args) throws Exception {
		Person p = new Person();
		System.out.println(p);
		//首先获取类的字节码对象
		Class c = p.getClass();
		//获取age这个成员变量
		Field f = c.getField("age");
		//给p对象的f成员变量,赋23值
		f.set(p, 23);
		System.out.println(p);
	}
}

暴力反射

1、通过Class类中:
getDeclaredXxx方法:可以获取类中的所有声明的成员(属性、方法、内部类),私有的成员也可以获取到。
2、修改该对象的访问权限:
成员变量、构造方法还是成员方法,都是AccessibleObject类型的子类,就具有判断是否可以访问,和设置是否可以访问的方法
isAccessible():判断当前对象是否可以访问
setAccessible(boolean flag):设定当前对象是否可以访问
3、一旦设定当前对象可以访问,私有的成员也可以被访问,被修改

import java.lang.reflect.Field;

public class Demo07_暴力反射 {
	public static void main(String[] args) throws Exception {
		Person p = new Person();
		//获取Person的字节码对象
		Class c = p.getClass();
		//获取Person类中的age成员变量,由于age是私有属性,所以需要使用getDeclaredField
		Field f = c.getDeclaredField("age");
		//判断该成员变量是否可以访问
		System.out.println(f.isAccessible());
		//将该成员变量设置为可以访问的权限
		f.setAccessible(true);
		System.out.println(f.isAccessible());
		//使用f的set方法,将p对象的f属性,设置为23这个值
		f.set(p, 23);
		System.out.println(p);
	}
}```


获取类中的成员方法并且执行

1、通过Class类中:
getMethod(String methodName, Class…paramTypes)
参数列表:methodName表示方法名称,paramTypes表示参数列表的数据类型
返回值类型:Method
2、Method类型:
1、表示成员方法的类型,该类型的每个对象,都是一个具体的成员方法
2、成员方法对象的方法:获取成员方法信息(方法的注解、方法的修饰符、方法的返回值类型、方法的名称、方法的参数)
3、其中,最重要的一个方法,就是该方法的执行:
invoke(Object obj, Object…values)
在obj对象上,执行该方法,使用的实际参数是values

mport java.lang.reflect.Method;

public class Demo08_获取成员方法并执行 {

	public static void main(String[] args) throws Exception {
		Person p = new Person();
		//获取设置age的方法,就先获取Person类型的字节码对象
		Class c = p.getClass();
		//方法的名称:setAge
		Method m = c.getMethod("setAge", int.class);
		//给p的age属性赋值为123,不能使用暴力反射
		m.invoke(p, 123);
		
		System.out.println(p);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值