反射基础理念和用法

反射

1. 反射的基本概念

什么是反射

反射:在程序运行时动态的探知修改类的结构。反射是java一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的方法,属性,构造方法等成员。

反射在实际开发中的应用

开发IDE(集成开发环境)

以上的IDE内部都大量使用了反射机制,我们在使用这些IDE写代码也无时无刻的使用着反射机制,一个常用反射机制的地方就是当我们通过对象调用方法或访问属性时,开发工具都会以列表的形式显示出该对象所有的方法或属性,以供方便我们选择使用。

这些开发工具之所有能够把该对象的方法和属性展示出来就使用利用了反射机制对该对象所有类进行了解剖获取到了类中的所有方法和属性信息,这是反射在IDE中的一个使用场景。

各种框架的设计

以上三个图标上面的名字就是Java的三大框架,简称SSH.

这三大框架的内部实现也大量使用到了反射机制,所有要想学好这些框架,则必须要求对反射机制熟练了。

使用反射机制解剖类的前提

必须先要获取到该类的字节码文件对象,即 Class类型对象。关于Class描述字节码文件如下图所示:

说明:

Java中使用Class类表示某个class文件

任何一个class文件都是Class这个类的一个实例对象.

1.获取Class字节码对象的三种方式

创建测试类:Student

public class Student {

static {

​ System.out.println(“静态代码块”);

}

{

​ System.out.println(“构造代码块”);

}

}

方式1:通过类名.class获取

//通过.class获得Student.class 字节码对象  -->返回Class类对象
   	Class<?> clazz = Student.class;
   	System.out.println(clazz);

方式2:通过Object类的成员方法getClass()方法获取

//通过Object类的getClass方法获得类对象
   	Student s = new Student();
   	Class<?> class1 = s.getClass();
   	System.out.println(class1);

方式3:通过Class.forName(“全限定类名”)方法获取

public void test3() throws ClassNotFoundException {
		//通过Class.forName("类的全限定名");
		Class<?> class1 = Class.forName("com.gec.reflect.Student");
		System.out.println(class1);
	}

2.获取Class对象的信息

知道怎么获取Class对象之后,接下来就介绍几个Class类中常用的方法了。

Class对象相关方法

String getSimpleName(): 获得简单类名,只是类名,没有包

	Class<?> class1 = Student.class;
		String simpleName = class1.getSimpleName();
		System.out.println(simpleName);

String getName(): 获取完整类名,包含包名+类名

Class<?> class1 = Student.class;
		String name = class1.getName();
		System.out.println(name);

T newInstance() :创建此 Class 对象所表示的类的一个新实例。要求:类必须有public的无参数构造方法

Class<?> class1 = Student.class;
		Object obj = class1.newInstance();
		System.out.println(obj);

3.获取Class对象的Constructor信息

一开始在阐述反射概念的时候,我们说到利用反射可以在程序运行过程中对类进行解剖并操作里面的成员。而一般常操作的成员有构造方法,成员方法,成员变量等等,那么接下来就来看看怎么利用反射来操作这些成员以及操作这些成员能干什么,先来看看怎么操作构造方法。而要通过反射操作类的构造方法,我们需要先知道一个Constructor类。

Constructor类概述

Constructor是构造方法类,类中的每一个构造方法都是Constructor的对象,通过Constructor对象可以实例化对象。

Class类中与Constructor相关方法

Constructor getConstructor(Class… parameterTypes)

根据参数类型获取构造方法对象,只能获得public修饰的构造方法。

如果不存在对应的构造方法,则会抛出java.lang.NoSuchMethodException 异常。

   Class<?> class1 = Student.class;
   	Constructor<?> public_c = class1.getDeclaredConstructor(String.class,String.class,int.class);
   	System.out.println(public_c);
   	
   	//创建对象
   	Student s = (Student)public_c.newInstance("admin","男",23);
   	System.out.println(s);

Constructor getDeclaredConstructor(Class… parameterTypes)

根据参数类型获取构造方法对象,能获取所有的构造方法,包括private修饰的构造方法。

如果不存在对应的构造方法,则会抛出 java.lang.NoSuchMethodException 异常。

Class<?> class1 = Student.class;
   	Constructor<?> private_c = class1.getDeclaredConstructor(String.class,String.class);
   	System.out.println(private_c);
   	
   	//暴力反射
   	private_c.setAccessible(true);
   	
   	Object obj = private_c.newInstance("admin","男");

Constructor[] getConstructors()

获取所有的public修饰的构造方法

Class<?> class1 = Student.class;
   	//获取所有的public的构造器
   	Constructor<?>[] cs = class1.getConstructors();
   	//打印构造器个数
   	System.out.println(cs.length);
   	
   	//循环
   	for (Constructor<?> c : cs) {
   		System.out.println(c);
   	}

Constructor[] getDeclaredConstructors()

获取所有构造方法,包括public、privat、默认、protected修饰的

Class<?> class1 = Student.class;
   	Constructor<?>[] cs = class1.getDeclaredConstructors();
   	System.out.println("所有的构造器:" + cs.length);
   	//循环
   	for (Constructor<?> c : cs) {
   		System.out.println(c);
   	}

Constructor类中常用方法

T newInstance(Object… initargs) :根据定参数创建对象。

void setAccessible(true) : 暴力反射,除public修饰的构造方法外,其他构造方法反射都需要暴力反射

4.获取Class对象的Method信息

操作完构造方法之后,就来看看反射怎么操作成员方法了。同样的在操作成员方法之前我们需要学习一个类:Method类。

Method类概述

1、 Method是方法类,类中的每一个方法都是Method的对象,通过Method对象可以调用方法。

Class类中与Method相关方法

1、 Method getMethod(“方法名”, 方法的参数类型… 类型)

根据方法名和参数类型获得一个方法对象,只能是获取public修饰的

2、Method getDeclaredMethod(“方法名”, 方法的参数类型… 类型)

根据方法名和参数类型获得一个方法对象,包括private修饰的

3、Method[] getMethods()

获取所有的public修饰的成员方法,包括父类中。

Method[] getDeclaredMethods()

获取当前类中所有的方法,包含私有的,不包括父类中。

Method类中常用方法

1、Object invoke(Object obj, Object… args)

根据参数args调用对象obj的该成员方法.如果obj=null,则表示该方法是静态方法

2、 void setAccessible(boolean flag)

暴力反射,设置为可以直接调用私有修饰的成员方法

示例代码

public class Demo4 {
   
   Class<?> class1 ;
   
   //每次运行@Test方法前会先执行有@Before的方法
   @Before
   public void before() {
   	class1 = Student.class;
   }
   
   //通过反射获取方法对象
   @Test
   public void test() {
   	Method[] methods = class1.getMethods();
   	System.out.println("methods.length:" + methods.length);
   	for (Method method : methods) {
   		System.out.println(method);
   	}
   }
   
   //获取所有的方法
   @Test
   public void test2() {
   	Method[] methods = class1.getDeclaredMethods();
   	System.out.println("methods.length:" + methods.length);
   	for (Method method : methods) {
   		System.out.println(method);
   	}
   }
   
   //获取指定的静态方法 不需要对象调用的,是由类名调用
   @Test
   public void test3() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
   	Method method = class1.getDeclaredMethod("study");
   	//调用方法 null:不需要传对象
   	method.invoke(null);
   }
   
   //获取指定的静态私有方法 不需要对象调用的,是由类名调用
   @Test
   public void test4() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
   	Method method = class1.getDeclaredMethod("studyX");
   	
   	//修改访问权限
   	method.setAccessible(true);
   	//调用方法 null:不需要传对象
   	method.invoke(null);
   }
   
   //先获取实例方法 ,创建对象,再调用
   @Test
   public void test5() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
   	Method method = class1.getDeclaredMethod("eat");
   	
   	//创建对象  class1.newInstance() => new Student();
   	Student stu = (Student) class1.newInstance();
   	
   	//stu.eat();
   	method.invoke(stu);
   }
   
   @Test
   public void test6() throws Exception {
   	//public void sleep(int hour){
   	Method method = class1.getDeclaredMethod("sleep",int.class);
   	
   	//创建对象  class1.newInstance() => new Student();
   	Student stu = (Student) class1.newInstance();
   	
   	//stu.sleep(7);
   	method.invoke(stu,7);
   }
   
   //私有的,实例方法   private void show()
   @Test
   public void test7() throws Exception {
   	//public void sleep(int hour){
   	Method method = class1.getDeclaredMethod("show");
   	
   	//设置方法可以访问 
   	method.setAccessible(true);
   	
   	//创建对象  class1.newInstance() => new Student();
   	Student stu = (Student) class1.newInstance();
   	
   	//stu.show();
   	method.invoke(stu);
   }

5.获取Class对象的Field信息

Field类概述

Field是属性类,类中的每一个属性(成员变量)都是Field的对象,通过Field对象可以给对应的成员变量赋值和取值。

Class类中与Field相关方法

1、 Field getDeclaredField(String name)

根据属性名获得属性对象,包括private修饰的

2、Field getField(String name)

根据属性名获得属性对象,只能获取public修饰的

3、 Field[] getFields()

获取所有的public修饰的属性对象,返回数组。

4、Field[] getDeclaredFields()

获取所有的属性对象,包括private修饰的,返回数组。

Field类中常用方法

设置属性

void set(Object obj, Object value)

void setInt(Object obj, int i)

void setLong(Object obj, long l)

获取属性

Object get(Object obj)

int getInt(Object obj)

long getLong(Object obj)

void setAccessible(true) 暴力反射,设置为可以直接访问私有类型的属性。

Class getType() 获取属性的类型,返回Class对象。

setXxx方法都是给对象obj的属性设置使用,针对不同的类型选取不同的方法。

getXxx方法是获取对象obj对应的属性值的,针对不同的类型选取不同的方法。

具体代码:

public class Demo5 {
	Class<?> class1 ;
	
	//每次运行@Test方法前会先执行有@Before的方法
	@Before
	public void before() {
		class1 = Student.class;
	}
	
	//获取所有public 修改的字段
	@Test
	public void test() {
		Field[] fields = class1.getFields();
		System.out.println("fields.length:" + fields.length);
		
		for (Field field : fields) {
			System.out.println(field);
		}
	}
	
	//获取Student类的所有字段,包括private/public/protected/default
	@Test
	public void test2() {
		Field[] fields = class1.getDeclaredFields();
		System.out.println("fields.length:" + fields.length);
		
		for (Field field : fields) {
			System.out.println(field);
		}
	}
	
	//获取指定的字段 name是private 
	@Test
	public void test3() throws NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
		Field field = class1.getDeclaredField("name");
		
		//暴力反射
		field.setAccessible(true);
		
		//创建对象
		Object obj = class1.newInstance();
		
		field.set(obj, "admin");
		
		System.out.println(obj);
	}
	
	@Test
	public void test4() throws NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
		Field field = class1.getDeclaredField("sex");
		
		//创建对象
		Object obj = class1.newInstance();
		
		// stu.sex="男"
		field.set(obj, "男");
		
		System.out.println(obj);
	}
	
	
}



class1.getDeclaredField("name");
		
		//暴力反射
		field.setAccessible(true);
		
		//创建对象
		Object obj = class1.newInstance();
		
		field.set(obj, "admin");
		
		System.out.println(obj);
	}
	
	@Test
	public void test4() throws NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
		Field field = class1.getDeclaredField("sex");
		
		//创建对象
		Object obj = class1.newInstance();
		
		// stu.sex="男"
		field.set(obj, "男");
		
		System.out.println(obj);
	}
	
	
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值