Java的反射机制,内含超简单实例代码(搞懂反射,这一篇就够了)

首先来说说反射机制的概念:
程序在运行时,
对于类来说,可以知道该类的任意属性和方法;
对于对象来说,可以调用该对象的任意方法和属性;

就以上这种动态获取信息的机制就称为Java的反射机制
彻底了解反射之前,我们还需要知道一个知识点:一般情况下,Java类在编译前,该类的相关数据就已经被加载到JVM中,而我们的反射机制可以在程序运行时,去操作类的方法,属性等,这种操作就很动态。

简单了解之后,相信有点理解,但是还是不能完全理解,那就通过下面这个说明,通过将这个概念和我们所熟悉的概念进行比较,可以让我们容易理解:
在Java编译中,主要有两种编译方式 :
静态编译:例如在我们编写程序,使用new关键字创造对象,在编译的时候,就会确定对象类型和所绑定的对象
动态编译:所谓动态编译,就是在运行时,才进行编译,使用的是newInstance()这个方法,稍后会讲解.

优点:
这样体现了Java的灵活性,多态特性同时也降低了类之间的耦合,spring容器中的类,就是这样执行的,降低了模块之间的耦合。
缺点:
因为该反射机制,是在jvm中执行,所以其相当于比静态编译多了这些步骤,其时间上就不如静态编译。
同时由于该绕过了该类的源码,容易对内部逻辑结构造成干扰。

三根据其特性有如下应用场景:
特性:可以动态获取正在运行程序类的属性或方法等和调用对象的方法
场景:动态代理,工厂模式优化,Java jdbc数据库操作等
下面会使用实际例子来说明该特性

四反射机制的具体实现
反射机制的实现主要通过java.lang.class类来进行操作
java.lang.class:
定义:java.lang.class类是反射机制的基础
作用:该类中存放了对应类型对象运行时的信息

前面说了,在java编译前,就已经存在于jvm中,在运行时,jvm会为运行时的类创建一个java.lang.class对象,用来维护对象的运行
而且该class中,存放着对应对象的所有运行时信息,就好比是将对该运行时对象信息的一个备份
且每个class类的实例对象的加载类都只有一个,好比每个class类都是一个模板,而该class类new出来的实例对象都是根据该模板生成的,所以即使一个class类有多个实例对象但是其getClass的结果都是一样的
如下例子

//对于2个String类型对象,它们的class对象就是同一个
Class a1="che".getClass();
Class a2=Class.forName("java.lang.class")
System.out.println(a1==a2)
//结果返回为True,因为该引用指向的是同一个Class 对象

同时Java的反射机制,除了获取最基本的Class对象,还需要获取另外三个类对象,Construction类,Method类和Field类
要这三个类的意义在于获取和调用运行时对象的构造方法,方法和属性。

使用反射机制的大致流程:
1获取目标类型的Class对象

2通过Class对象,来获取Construction类对象Method类对象Field类对象

3通过Construction类对象,Method类对象和Field类对象来获取运行时对象的构造方法方法属性,然后对其进行各种操作
接下来,我们来详解讲解每个步骤:
步骤1:获取目标类型的Class对象

//获取目标类型的class对象
//1使用Object.getClass()获取------该方法会返回一个Class类型的实例
Boolean che=true;
Class  cheType=che.getClass();
System.out.println(cheType);
//输出的结果是class  java.lang.Boolean 

//2Static method class.forName
Class<?>  cheType=Class.forName("java.lang.class");
//使用时,应提供异常处理器
System.out.println(cheType);
//输出结果:class  java.lang.Boolean

通过Class对象分别获得Construction类对象,Method类对象和Field类对象
/一 通过Class对象获取类的构造方法/

//重点:下面会出现declared这个词,这是公共的意思,公共类,若方法中使用了该关键字,那么取出的就只是和公共类有关系的,与继承类无关
//a获取指定的构造方法(传入构造函数的参数类型,包括公共和继承)
Constructor<T> getConstructor(Class<?>.... parameterTypes)
// b获取所有的构造方法(只包括公共) 
Constructor<?>[] getConstructors()
//c获取指定的构造方法(传入构造函数的参数类型 只包含公共不包含继承)
Constructor<T> getDeclaredConstructor(Class<?>...parametrTypes)
//d获取所有的构造方法(public,private等修饰的都会获取)
Constructor <?> getDeclaredConstructors()

/二 通过Class对象获取类的方法/

//a和上面类似,获取指定的方法,就需要传入对应的方法名&参数类型,包括公共和继承
Method   getMethod(String name,Class<?> ...parameterTypes)
// b 获取公共(public)方法
Method[]   getMethods()
//c获取指定的方法
Method   getDeclaredMethod(String name,Class<?>...parametrTypes)
//d获取所有的方法(public,private等修饰的都会获取)
Method[]   getDeclaredMethods()

/三通过Class对象获取类的属性/

//a和上面类似,获取指定的属性,就需要传入对应的属性名,包括公共和继承
FIeld   getFIeld(String name)
// b获取所有的属性(只包括公共) 
FIeld[]   getFIelds()
//c获取指定的属性( 
FIeld   getDeclaredFIeld(Class<?>...parametrTypes)
//d获取所有的属性(public,private等修饰的都会获取)
FIeld[]   getDeclaredFIelds()

/四除了上面那些方法,还有一些比较常用的方法/

//返回完整的类名(例如java.lang.Boolean)
String getName();

//创建一个实例,/调用默认的构造器,若该类无构造器,则会抛出异常/
Object newInstance()

以上我们就完成了第二步,分别获取了其他三个类对象,接下来我们就使用对应的类对象来完成对目标对象的操作

/一通过Constructor对象来获取类的构造方法并进行操作/
Modifiers//修饰符的意思

String getName();//获取构造器名
Class getDeclaringClass();//获取类中构造器的Class对象
int getModifies();//返回整型数字,用不同的位开关描述访问修饰符的使用状况,好比返回的是状态码
Class[] getExceptionTypes();//获取描述抛出的异常方法类型的Class对象数组
Class[] getParameterTypes();//获取参数类型的Class 对象数组

/二通过Method对象来获取类的方法并进行操作/

String  getName();//获取方法名
Class getDeclaringClass()://获取类中方法的Class对象
int getModifiers();//返回整型数值,用不同的状态码来描述访问修饰符的使用状况
Class getExceptionTypes();//获取用于描述抛出异常方法类型的Class对象数组
Class getParameterTypes();//获取一个用于描述参数类型的Class对象数组

/三通过Field对象来获取类的属性并进行操作/

String  getName();//获取对应的属性名
Class getDeclaringClass();//获取类中属性的Class对象
Class getType();//获取属性类型的Class对象
int getModifiers();//返回整型数值用不同的位开关来描述访问修饰符的使用状况
Object get(Object obj);//返回指定对象上,此属性的值
void set(Object obj,Object value);//给指定对象的属性赋值
//另外还有以下两个方法
//获取对应mofidiers位设置的修饰符
static String toString(int modifiers)
//检查方法名中对应的修饰符在modifiers中的值
static boolean isXXX(int modiers)

这样,我们关于Java的反射机制的大致流程就讲完了

五反射机制一定要关注的几点,简单易懂且重要
1在Java中,有一种安全机制,该机制只允许对运行时的程序进行访问操作,不允许进行修改等操作
2另外还有一种,是关于访问权限的,和封装有关,不允许访问被private修饰的方法或字段
以上两点,刚好和我们的反射机制有冲突,要想完整实现我们的反射机制,就需要脱离安全机制的管控,屏蔽掉访问权限的检查,从而为所欲为。
见下

//为了达到为所欲为的目的,我们可以采用Constructor,Method和Field的setAccessible方法来实现
//为反射机制设置可以访问的标志
void setAccessible(boolean flag)
//flagtrue时,可以脱离管控,
boolean  isAccessible()
//获得该值,判断是否已经脱离管控
static void setAccessible(AccessibleObject[] array,boolean flag)
//设置对象数组可以访问的标志,

六到这里,关于反射机制我们已经了解了,接下来我们就来进行实践吧!
实例1,利用发射机制调用类的构造方法:

package stu;

public class FanShe {
	/*
	 * 分别创造一个无参构造器和有参构造器
	 * 
	 */
	private String name;
public FanShe(){
	System.out.println("创建了一个无参数的反射实例");
}
public FanShe(String name){
	System.out.println("创建了一个有参数的反射实例");
}
}
------------------------------------------------------------------------------------------
package stu;

import java.lang.reflect.InvocationTargetException;

public class MainTest{	
	//获取FanShe的Class对象
	public static void main(String args[]) {
Class fansheClass=FanShe.class;
	//通过Class对象获取Constructor类对象,从而调用无参构造方法(反射机制中,创建对象是使用newInstance(),此方法和new很像)
try{
Object obj1=fansheClass.getConstructor().newInstance();
Object obj2=fansheClass.getConstructor(String.class).newInstance("name");
}
catch(InstantiationException e){
	e.printStackTrace();
}
catch(IllegalAccessException e){
	e.printStackTrace();
}
catch(InvocationTargetException e){
	e.printStackTrace();
}
catch(NoSuchMethodException e){
	e.printStackTrace();
}
}
}

------------------------------执行结果
创建了一个无参数的反射实例
创建了一个有参数的反射实例

实例2:利用反射机制调用类对象的方法

package stu;

public class FanShe2 {
	private String name;
	
	public FanShe2()
	{
		System.out.println("使用反射机制来获取类对象的属性");
	}
}
---------------------------------------------
package stu;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class MainTest2 {
   
	public static void main(String args[]){
		//1获取Fanshe2的Class类对象
		Class f2class=FanShe2.class;
		try{
		//2通过Class对象来创建FanShe2类的对象
		Object object1=f2class.newInstance();
		//3通过Class对象和Field类对象来获得FanShe2类的name属性
		Field f=f2class.getDeclaredField("name");
		//4设置私有访问权限,脱离管控
		f.setAccessible(true);
		//5通过Field的类对象对新创建的FenShe2对象object1的name属性设置值,void set(Object obj,Object value)
		f.set(object1, "成功赋值");
		//6获取新创建FanShe2对象的name属性&输出
		System.out.println(f.get(object1));
	}
   catch(InstantiationException e){
	e.printStackTrace();
}
   catch(IllegalAccessException e){
	e.printStackTrace();
} catch (SecurityException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
} catch (NoSuchFieldException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

}
}
-----------------------执行结果
使用反射机制来获取类对象的属性
成功赋值

实例3:利用反射机制来调用类对象的方法

package stu;
/*
 * 分别创建一个无参和一个有参的方法
 */
public class FanShe3 {

	public FanShe3(){
		System.out.println("通过反射机制来调用类对象的方法");
	}
	public void Test1(){
		System.out.println("Test1 我是一个无参方法");
	}
	public void Test2(String str){
		System.out.println("Test2 我是一个名为"+str+"有参方法");
	}
}
-----------------------------------------------------------------
package stu;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MainTest3 {
	public static void main(String args[]){
		//1创建FanShe3类的Class对象
		Class f3class=FanShe3.class;
		try {
		//2通过Class类,创建FanShe3类的对象
		Object object=f3class.newInstance();
		//3通过Class对象获取Test1()方法:需要传入方法名
		Method test11=f3class.getMethod("Test1");
		//4通过Class对象获取Test2()方法:需要传入方法名&参数类型
		Method test22=f3class.getMethod("Test2", String.class);
		//5通过Method对象,传入对应的参数,.invoke调用的意思,调用FanShe3对应的方法
		test11.invoke(object);
		test22.invoke(object, "Rapper");
		}  catch(InstantiationException e){
			e.printStackTrace();
		}
		   catch(IllegalAccessException e){
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}  catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}
-----------------------------执行结果
通过反射机制来调用类对象的方法
Test1 我是一个无参方法
Test2 我是一个名为Rapper有参方法

此致,Java的反射机制,就已经完全讲解清楚了,

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java反射机制是在运行时动态地获取类的信息,包括类名、方法名、属性等,并且可以在运行时调用对象的方法和访问对象的属性。下面是一个简单Java反射机制实例: 假设我们有一个Person类,其包含以下属性和方法: ```java public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public void sayHello() { System.out.println("Hello, my name is " + name + ", and I am " + age + " years old."); } } ``` 现在我们可以使用反射机制来获取Person类的信息并创建它的实例: ```java import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class ReflectionExample { public static void main(String[] args) throws Exception { // 获取Person类的Class对象 Class<Person> personClass = Person.class; // 获取Person类的构造函数 Constructor<Person> constructor = personClass.getConstructor(String.class, int.class); // 创建Person类的实例 Person person = constructor.newInstance("John", 30); // 获取Person类的name属性 Field nameField = personClass.getDeclaredField("name"); nameField.setAccessible(true); // 修改Person类的name属性 nameField.set(person, "Tom"); // 调用Person类的sayHello方法 Method sayHelloMethod = personClass.getDeclaredMethod("sayHello"); sayHelloMethod.invoke(person); } } ``` 在这个例子,我们首先使用`Person.class`获取Person类的Class对象,然后使用`getConstructor`方法获取构造函数,使用`newInstance`方法创建Person类的实例。 接下来,我们使用`getDeclaredField`方法获取Person类的name属性,并使用`setAccessible`方法设置该属性可访问。然后,我们使用`set`方法修改该属性的值。 最后,我们使用`getDeclaredMethod`方法获取Person类的sayHello方法,并使用`invoke`方法调用该方法。 这个例子只是反射机制的一个简单示例,反射机制还可以应用于许多其他方面,例如动态代理、注解处理等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值