Java反射之------访问类的属性和方法

什么是反射 ?

Java反射就是在运行状态时,对任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性。而这也是Java被视为动态语言的关键原因。

在具体的研发中,通过反射获取类的实例,大大提高系统的灵活性和扩展性,同时由于反射的性能较低,而且它极大的破坏了类的封装性(通过反射可以获取类的私有属性和方法),在大部分场景下并不适合使用反射,但是在大型的一些框架中,会大范围的使用反射来帮助架构完善一些功能。

反射所涉及到的一些类:

  • Class :类的类
  • Field : 属性
  • Method :方法
  • Constructor :构造方法

反射的实现:

首先准备一个 Student 类:

package com0911;

public class Student {
	
	public String name;
	protected int age;
	private char sex;
	
	public Student(){
		
	}
	
	public Student(String name,int age,char sex){
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
	
	public void getName(){
		System.out.println("getName()方法被访问了!");
		System.out.println(name);
	}
	
	protected void getAge(){
		System.out.println("getAge()方法被访问了!");
		System.out.println(age);
	}
	
	private void getSex(){
		System.out.println("getSex()方法被访问了!");
		System.out.println(sex);
	}
	
	private void A(String str,int a,char ch){
		System.out.println(str);
		System.out.println(a);
		System.out.println(ch);
	}

}

反射类:
(我们会在这个类中使用反射访问Student类中的属性和方法)


public class Reflect {
	
	//反射访问属性和不带参数的方法
	public void create_without_parameter(){
		
		try {
			//获取Class对象
			Class cla = Class.forName("com0911.Student");
			//获取类的构造方法
			Constructor con = cla.getConstructor();
			//创建对象
			Object obj = con.newInstance();
			//将属性存放在fields[]数组中
			Field[] fields = cla.getDeclaredFields();
			//输出属性
			for(int i=0;i<fields.length;i++){
				//获取类的属性
				String name = fields[i].getName();
				fields[i].setAccessible(true);
				//访问类的属性
				Object value = fields[i].get(obj);
				System.out.println(name+" "+value);
				//修改属性的值
				value = "change!";
				System.out.println("属性修改后: "+name+" "+value);
				System.out.println("-------------------------");
			}
			//获取类的方法
			Method[] methods = cla.getDeclaredMethods();
			for(int i=0;i<methods.length;i++){
				//对属性设置访问权限,当类中方法为Protected和private时必须设置此项为true
				methods[i].setAccessible(true);
				methods[i].invoke(obj);
				System.out.println("-------------------------");
			}
		} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	//反射访问属性和带参数的方法
	public void create_with_parameter(){
		try {
			//获取Class对象
			Class cla  = Class.forName("com0911.Student");
			//参数类型数组
			Class[] parameterTypes = {String.class,int.class,char.class};
			//根据参数类型获取相应的构造函数
			Constructor con = cla.getConstructor(parameterTypes);
			//参数数组(初始化)
			Object[] parameters = {"小明",19,'m'}; 
			//创建对象
			Object obj = con.newInstance(parameters);
			//获取属性,将属性存放在fields[]数组中
			Field[] fields = cla.getDeclaredFields();	//getField()获取一个类的public字段,getDeclaredField()获取一个类的所有字段
			for(int i=0;i<fields.length;i++){
				//获取类的属性
				String name = fields[i].getName();
				fields[i].setAccessible(true);
				Object value = fields[i].get(obj);
				System.out.println("初始化之后的属性值: "+name+": "+value);
				System.out.println("-------------------------");
			}
			//getDeclaredMethod()方法中第一个参数表示方法名,第二个参数表示参数类型
			Method method = cla.getDeclaredMethod("A",String.class,int.class,char.class);
			method.setAccessible(true);
			//调用方法时传入参数
			method.invoke(obj, "小明",18,'m');
			
  		} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	public static void main(String[] args){
		Reflect reflect = new Reflect();
		reflect.create_with_parameter();
		reflect.create_with_parameter();
	}

}

reflect.create_without_parameter();
(不带参数)
样例输出:
name null
属性修改后: name change!
-------------------------
age 0
属性修改后: age change!
-------------------------
sex 
属性修改后: sex change!
-------------------------
getName()方法被访问了!
null
-------------------------
getAge()方法被访问了!
0
-------------------------
getSex()方法被访问了
reflect.create_with_parameter();
(带参数)
样例输出:
初始化之后的属性值: name: 小明
-------------------------
初始化之后的属性值: age: 19
-------------------------
初始化之后的属性值: sex: m
-------------------------
A()方法被访问了!
小明
18
m

上面是总的代码的实现,但是在我们实现的过程中会遇到一些问题,下面我将我在实现过程中遇到的一些问题和大家分享一下,期待对大家有所帮助。

  • getField()和 getDeclaredFields()方法的区别

getField ()方法是获取一个类的public字段,也就是它可以获取一个类中所有访问权限为public的属性和方法。而 getDeclaredFields()方法是获取一个类的所有字段。

  • 关于setAccessible(true)的使用

在写代码的过程中,我们会发现如果要在类外访问里一个类的私有属性和方法时,系统会报错。这个时候就需要使用setAccessible()方法了。setAccessible()是对属性设置访问权限,当类中方法为Protected和private时必须设置此项为true。

总结:

在反射过程中,我们可能会遇到一下几种情况:

  1. 访问public、protected、private属性
  2. 访问public、protected、private方法
  3. 访问不带参数的方法
  4. 访问带有参数的方法

上述情况在上面的代码中都有涉及到,想深入了解的小伙伴可参考源码学习。

可承接各种项目,有意者加QQ:1217898975

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

steven_moyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值