Java反射机制-粗暴的java基础内容

1.java反射机制是java基础中比较重要的内容
2.java反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;
3.java反射机制在许多框架中都有很好的应用,比如hibernate框架等
4.下面我将为大家进行相关演示以及呈现java反射机制原理以及主要方法等

1、JAVA反射机制的简介及其原理

1.1 java反射机制简介

	1. java反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;
	2. java反射机制其实就是通过获取字节码文件来获取你的类对象,也就是.class对象,然后进行暴力对此对象进行操作;
	3. java反射机制在获取授权(一行代码)之后,便可以对私有成员和私有方法进行直接获取值或赋值。
	4. 如果到这里还没理解,请移步百度查一下,下面主要讲解应用,不准备在原理上花太多时间,因为个人能力问题,怕误导大家,此博客仅作为码农的中转站,并非终点站

1.2 java反射机制原理

  1. 一个.java源码文件,进行编译后会生成.class的字节码文件,然后通过ClassLoader将其加载到内存当中,所有的成员变量都加载成为了Field对象,所有的构造方法都加载成为了Constructor对象,所有的成员方法都加载成为了Method对象,那么此时我们便可以对其进行操作。

  2. 对于获取.class文件(上文所述的字节码文件对象),主要有三种方式,我们以Person为自己构建的类对象进行举例,如下代码;
    (1)通过类名属性进行获取,多用于参数传递,比如hibernate框架中常用此方法
    Class person01 = Person.class;
    (2)通过Class.forName(“全路径”)进行获取,此方法常用于配置文件,比如在Mybatis框架中便采用了此方法
    Class person02 = Class.forName("cn.hnist.ly.model.Person");
    (3)通过 .getClass()函数获取,多用于获取字节码。抱歉我才疏学浅,此类方法我没实践过,但是我用上面两种办法写过自己的jdbc连接框架,当然涉及到的知识点不仅仅这些…
    Person p = new Person();
    Class person03 = p.getClass();

  3. 当我们了解这些,并获取了Class对象后便可以对此进行相关操作了,具体代码如下文

2、JAVA反射机制的演示

2.1 对类成员变量(field对象)的操作

1.对于类的成员变量,本处主要介绍获取成员变量,以及获取值和成员对象进行直接赋值的操作
2.不会面面俱到,点到为止说些常用的
3.获取类对象主要采用常用的传参方式,也就是.getClass()方式进行

2.1.1 获取Field成员变量

1 使用 getField 方法获取成员变量(获取的是所有的public修饰的成员变量)

代码:

/**
 * 主方法
 **/
public static void main(String[]args) throws Exception {

		//构造一个Persong对象
		Person person = new Person("aContent", "bContent", "cContent", "dContent");
		
		//获取其Class文件
		Class personClass = person.getClass();
		
		//通过getField方法获取所有的field对象(成员变量)
		Field[] fields = personClass.getFields();  //下文中直接将getField改为getDeclaredFields的地方
		
		System.out.println("*****************************************************************************");
		//打印
		for (Field field : fields) {
			
			System.out.println("成员变量为:"+field);
			
			System.out.println("成员变量名:"+field.getName());

			System.out.println("成员变量类型:"+field.getGenericType().getTypeName());.

			System.out.println("访问权限控制符:"+ Modifier.toString(field.getModifiers()) );
			
            System.out.println("*****************************************************************************");
		}
	}

/**
 * Person类 
 * 1. 此处忽略get set 以及构造方法等
 * 2. 后面的例子均以此为例进行操作
 * 
 **/
public class Person {
	
	public    String a;
	protected String b;
	          String c;
	private   String d;
}

运行结果:
在这里插入图片描述

2. 使用 getDeclaredFields 方法获取成员变量(获取的是所有的成员变量)

代码:

仅仅将上文中的 Field[] fields = personClass.getFields();
       更改为:Field[] fields = personClass.getDeclaredFields();
       其他的部分不变 运行结果如下图

结果为:
在这里插入图片描述

小结:
    1.getField() 方法仅能获取修饰符为public的成员变量
    2.getDeclaredFields()能获取所有的的成员变量
    3.除上述两点的区别外,其他的区别不大
3. 已知变量名的情况下,获取单个field对象的方法

代码01:

public static void main(String[]args) throws Exception {

		//构造一个Persong对象
		Person person = new Person("aContent", "bContent", "cContent", "dContent");
		
		//获取其Class文件
		Class personClass = person.getClass();

		//获取指定变量名为 a 的成员变量
		Field aField = personClass.getField("a");
		
		System.out.println("成员变量为:"+aField);
		
		System.out.println("成员变量名:"+aField.getName());

		System.out.println("成员变量类型:"+aField.getGenericType().getTypeName());

	}

结果:(当然获取别的非公有的变量则报错)
在这里插入图片描述
代码02:

public static void main(String[]args) throws Exception {

		//构造一个Persong对象
		Person person = new Person("aContent", "bContent", "cContent", "dContent");
		
		//获取其Class文件
		Class personClass = person.getClass();
		
	
		Field aField = personClass.getDeclaredField("d");
		
		System.out.println("成员变量为:"+aField);
		
		System.out.println("成员变量名:"+aField.getName());

		System.out.println("成员变量类型:"+aField.getGenericType().getTypeName());
		
		System.out.println("访问权限控制符:"+ Modifier.toString(aField.getModifiers()) );
		
		
	}

结果:
在这里插入图片描述

2.1.2 对获取的Field成员对象的值进行操作

1. 对共有的成员变量进行值操作处理

代码:

	
	public static void main(String[]args) throws Exception {

		//构造一个Persong对象
		Person person = new Person("aContent", "bContent", "cContent", "dContent");
		
		//获取其Class文件
		Class personClass = Person.class;
		
	
		Field aField = personClass.getField("a");
		
		//获取上文构造的person对象的值
		Object value = aField.get(person);
		
		//打印
		System.out.println("更改前值为:"+value);
		
		//更改
		aField.set(person, "aChange");
		
		//打印
		System.out.println("更改后值为:"+aField.get(person));
		
	}

结果:
在这里插入图片描述

2. 对私有的成员变量进行值操作处理.

代码:

	public static void main(String[]args) throws Exception {

		//构造一个Persong对象
		Person person = new Person("aContent", "bContent", "cContent", "dContent");
		
		//获取其Class文件
		Class personClass = Person.class;
		
	
		Field aField = personClass.getDeclaredField("d");
		
		//授权
		aField.setAccessible(true);
		
		//获取上文构造的person对象的值
		Object value = aField.get(person);
		
		
		
		//打印
		System.out.println("更改前值为:"+value);
		
		//更改
		aField.set(person, "aChange");
		
		//打印
		System.out.println("更改后值为:"+aField.get(person));
		
	}

结果:
在这里插入图片描述

小结:

1.原则上是不允许对类成员变量进行直接赋值或者更改的,最好是通过get或set方法
2.对于public修饰的成员变量,我们可以直接进行更改
3.对于非public的成员变量,我们需要进行授权操作才能进行更改

2.2 对构造方法的操作

1.对构造方法Constructor对象进行操作,常用于创建一个对象,比如本文中就可以创建一个Person对象,可以简单理解为Spring框架也使用了此方法
2.创建步骤跟上文演示的Field对象的创建差不多 也是需要先获取类对象之后再逐步实现
3.创建对象的方法主要是获取了他的构造方法

2.2.1 获取构造方法对象(Constructor对象)的方法

代码:

public static void main(String[]args) throws Exception {

		//构造一个Persong对象
		Person person = new Person("aContent", "bContent", "cContent", "dContent");
		
		//获取其Class文件
		Class personClass = Person.class;
		
	
		System.out.println("*************获取所有的构造方法**************\n");
		//获取构造方法之一,获取所有的构造方法
		Constructor[] constructors = personClass.getConstructors();
		
		for(Constructor constructor : constructors) {
			System.out.println("构造方法:"+constructor);
		}
		
		System.out.println("\n*************根据构造方法的参数获取构造方法*************\n");
		
		
		//根据构造方法的参数获取构造函数
		Constructor constructor02 = personClass.getDeclaredConstructor(String.class,String.class,String.class,String.class);
		System.out.println(constructor02);
		
		
	
	}

结果:
在这里插入图片描述

2.2.2 通过获取的构造方法对象创建对象

1.对于非空参数的构造方法创建对象

代码:

	public static void main(String[]args) throws Exception {

		//构造一个Persong对象
		Person person = new Person("aContent", "bContent", "cContent", "dContent");
		
		//获取其Class文件
		Class personClass = Person.class;
		
		
		//根据构造方法的参数获取构造函数
		Constructor constructor02 = personClass.getDeclaredConstructor(String.class,String.class,String.class,String.class);
		
		//对获取的构造方法对象进行创建Person对象的操作
		Object personObject = constructor02.newInstance("a","b","c","d");
		
		//打印
		System.out.println(personObject);

	}

结果:
在这里插入图片描述

2.对于空参数构造方法创建对象

方法一:就是将上文的方法去掉参数即可,本文不是很推荐使用这个方法,推荐使用方法二
方法二:

代码:

public static void main(String[]args) throws Exception {

		//构造一个Persong对象
		Person person = new Person("aContent", "bContent", "cContent", "dContent");
		
		//获取其Class文件
		Class personClass = Person.class;
		
		//创建一个空参的person对象
		Object personObject = personClass.newInstance();

		//打印
		System.out.println(personObject);
		
	
	}

结果:
在这里插入图片描述

小结(应用):

  1. 对于此类方法其实在Hibernate框架经常使用,返回的Object 进行强制转换成我们所需要的各类对象即可,但是也可能因为sql语句问题等造成错误(hibernate框架中)

  2. 自己在构建自己的jdbc的框架的时候也应该会经常用到

  3. spring框架管理创建的对象时候,我相信也会用到(本人还没看spring源码)

2.3 对成员方法的操作

2.3.1 获取类对象成员方法

  1. 获取方法和上文中的差不多,那么我就不再多做累赘,直接上代码
  2. 特别说明:获取成员方法时,不仅仅会获取自定义的成员方法,还会获取Object类的成员方法
  3. 获取method对象后,使用invoke方法进行运行,当然非公有的需要授权

2.3.1.1 获取全部的成员方法

代码:

public static void main(String[] args) throws Exception {

		//构造一个Persong对象
		Person person = new Person("aContent", "bContent", "cContent", "dContent");
		
		//获取其Class文件
		Class personClass = Person.class;
		
		//获取所有共有的成员方法
		Method[] methods = personClass.getMethods();
		
		//获取所有的成员方法
		//Method[] methods = personClass.getDeclaredMethods();
		
		//打印
		for (int i = 0; i < methods.length; i++) {
			System.out.println(methods[i]);
		}
		
	
	}

结果:
在这里插入图片描述

2.3.1.2 获取单个的成员方法

代码:

public static void main(String[]args) throws Exception {

		//构造一个Persong对象
		Person person = new Person("aContent", "bContent", "cContent", "dContent");
		
		//获取其Class文件
		Class personClass = Person.class;
		
		//获取getA()方法
		Method getAMethod = personClass.getDeclaredMethod("getA");
		
		//获取setA()方法 , 应为setA方法有个参数 String 故需要多传入一个参数
		Method setAMethod = personClass.getDeclaredMethod("setA", String.class);
		
		//打印
		System.out.println("getA()方法:"+getAMethod);
		System.out.println("setA()方法:"+setAMethod);

	}

结果:
在这里插入图片描述

2.3.2 运行获取的成员方法

1. 因为获取的是类对象,并非真正运行状态的对象,故需要先new 一个Person对象,然后以他为主体进行操作
2. 延续上文的代码
3. 运行非公有的成员方法时,需要在获取Method对象后使用setAccessible(true);进行授权,例如:setAMethod.setAccessible(true);

代码:

public static void main(String[]args) throws Exception {

		//构造一个Persong对象
		Person person = new Person("aContent", "bContent", "cContent", "dContent");
		
		//获取其Class文件
		Class personClass = Person.class;
		
		//获取getA()方法
		Method getAMethod = personClass.getDeclaredMethod("getA");
		
		//获取setA()方法 , 应为setA方法有个参数 String 故需要多传入一个参数
		Method setAMethod = personClass.getDeclaredMethod("setA", String.class);
		
		//打印
		System.out.println("getA()方法打印结果:"+getAMethod.invoke(person));
		
		//重新设置A值
		setAMethod.invoke(person, "AChange");
		
		//重新打印A
		System.out.println("getA()再次打印结果:"+getAMethod.invoke(person));
		

	}

结果:
在这里插入图片描述

本文总结

  1. java反射作为java基础内容,也是比较高级的难一点的基础内容,本文仅作为入门文档,在实际应用开发中会遇到各种情况,因为篇幅原因,本文先结束
  2. java反射的运用在某种情况下会违反一些原则,这些原则在java开发中应该是明文禁止或避免的,但是反射可以暴力执行,也必须需要反射进行暴力执行
  3. 各种各样的以人为本的框架离不开java反射的这一块内容,我接触比较多的就是spring全家桶以及jdbc的框架。不管你以后是使用市面上比较流行的框架还是自主开发一套,都离不开java反射的扶持,也希望引起大家的重视。
  4. 关于作者我本人能力有限,水平一般,如果有错误或者不好之处,希望读者看官多多斧正。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的公寓报修管理系统,源码+数据库+毕业论文+视频演示 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本公寓报修管理系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此公寓报修管理系统利用当下成熟完善的Spring Boot框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。公寓报修管理系统有管理员,住户,维修人员。管理员可以管理住户信息和维修人员信息,可以审核维修人员的请假信息,住户可以申请维修,可以对维修结果评价,维修人员负责住户提交的维修信息,也可以请假。公寓报修管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 关键词:公寓报修管理系统;Spring Boot框架;MySQL;自动化;VUE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值