Java使用反射获取类的属性和方法(实体类)

理解反射

  • 想要理解“反射”,就必须明白“正射”,他们最大的区别在于你是否知道其中的属性和方法,如果知道就是正射;反之,你根本就不知道你要运行的类是哪个,只知道路径,并且你想要使用这个类,就是反射。(个人理解)
  • 反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
  • 总结:动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
所谓的"正射"
  • 开发者自己建的类,我们知道其中的属性,和方法,由此我们可以通过new关键字来创建和适用对象,这就是“正射”。
所谓的"反射"
  • 开发者在不知道类的内容,想要知道该类的属性和方法,这个过程就叫做“反射”。
//这段代码我们理解为正
Apple apple = new Apple(); //直接初始化,「正射」
apple.setPrice(4);
//这段代码我们理解为反
Class clz = Class.forName("com.chenshuyi.reflect.Apple");
Method method = clz.getMethod("setPrice", int.class);
Constructor constructor = clz.getConstructor();
Object object = constructor.newInstance();
method.invoke(object, 4);

上面两段代码的执行结果,其实是完全一样的。但是其思路完全不一样,第一段代码在未运行时就已经确定了要运行的类(Apple),而第二段代码则是在运行时通过字符串值才得知要运行的类(com.chenshuyi.reflect.Apple)。

反射相关的类
类名用途
Class代表类的实体,在运行的Java应用程序中表示类和接口
Field代表类的成员变量(成员变量也称为类的属性)
Method代表类的方法
Constructor代表类的构造方法
Class类常用的方法
  • 类相关
方法用途
forName(String className)根据类名返回类的对象
newInstance()创建类的实例
getPackage()获得类的包
fgetInterfaces()获得当前类实现的类或是接口
getDeclaredClasses()返回一个数组,数组中包含该类中所有类和接口类的对象
  • 获取类成员变量相关
方法用途
getDeclaredField(String name)获得某个属性对象
getDeclaredFields()获得所有属性对象
getField(String name)获得某个公有的属性对象
getFields()获得所有公有的属性对象
  • 获取类构造器相关
方法用途
getConstructor(Class…<?> parameterTypes)获得该类中与参数类型匹配的公有构造方法
getConstructors()获得该类的所有公有构造方法
getDeclaredConstructor(Class…<?> parameterTypes)获得该类中与参数类型匹配的构造方法
getDeclaredConstructors()获得该类所有构造方法
  • 获得类中方法相关的方法
方法用途
getDeclaredMethods()获得该类所有方法
getDeclaredMethod(String name, Class…<?> parameterTypes)获得该类某个方法
getMethods()获得该类所有公有的方法
Field类
方法用途
getDeclaredFields()获取包括私有所有字段
getField(String name)获取公共字段
getType()返回一个Class对象
getGenericType()返回一个Type对象
Method类
方法用途
invoke(Object obj, Object… args)t调用方法时
getField(String name)获取公共字段
getType()返回一个Class对象
getGenericType()返回一个Type对象
  • 例子
Person类
package demo;

public class Person {

	private int age;
	
	private String name;
	
	private double price;
	
	public Person() {
		super();
	}

	public Person(int age, String name, double price) {
		super();
		this.age = age;
		this.name = name;
		this.price = price;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}
	
}

		try {
			Class<?> personClass = Class.forName("demo.Person");
			//初始化的时候必须要有显式的构造方法,即使是无参的
			Object instance = personClass.newInstance();
			Field[] declaredFields = personClass.getDeclaredFields();
			for (Field item : declaredFields) {
				String name = item.getName();
				Class<?> typeClass = item.getType();
				Type genericType = item.getGenericType();

				System.out.println(name + " 的变量类型为 " + genericType.toString() + ", typeClass为:" + typeClass.getName());
			}

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	

输出结果:要注意的是如果变量类型不是基本类型,则他的类型为 class.包名

age 的变量类型为 int, typeClass为:int
name 的变量类型为 class java.lang.String, typeClass为:java.lang.String
price 的变量类型为 double, typeClass为:double
		try {
			Class<?> personClass = Class.forName("demo.Person");
			Object instance = personClass.newInstance();
			Method[] declaredMethods = personClass.getDeclaredMethods();
			for (Method item : declaredMethods) {
				String name = item.getName();
				Type typeClass = item.getGenericReturnType();
				Type[] genericType = item.getGenericParameterTypes();
				if(genericType.length!=0) {
					System.out.println(name + " 的返回值为 " + typeClass.toString() + ", 参数值为:" + 
							genericType[0].toString());
				}
			}

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
输出结果:
setName 的返回值为 void, 参数值为:class java.lang.String
setAge 的返回值为 void, 参数值为:int
setPrice 的返回值为 void, 参数值为:double

项目中的例子:
    public void setObjectDefaultValue(Object obj){
        //获取obj的所有属性
        Method[] declaredMethods = obj.getClass().getDeclaredMethods();
        for(Method item : declaredMethods){
            String methName = item.getName();
            if(methName.substring(0,3).equals("set") && item.getGenericParameterTypes()[0].getTypeName().equals("double")){
                try {
                    item.invoke(obj,(double)Math.round((Math.random()*3000)*100)/100);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }

    }



    public void setObjectProperty(Object target, Object actual , Object assess,@Nullable Map<String, String> dif) {
        Field[] targetfiled = target.getClass().getDeclaredFields();
        Field[] actualfiled = actual.getClass().getDeclaredFields();
        Field[] assessfiled = assess.getClass().getDeclaredFields();

        for(int i =0 ;i<targetfiled.length;i++){
            Field item = targetfiled[i];
            String typeName = item.getGenericType().toString();
            if(typeName.equals("double")){
                String propertName = item.getName();
                StringBuffer getbf = new StringBuffer();
                getbf.append("get");
                getbf.append(propertName.substring(0,1).toUpperCase());
                getbf.append(propertName.substring(1));

                StringBuffer setbf = new StringBuffer();
                setbf.append("set");
                setbf.append(propertName.substring(0,1).toUpperCase());
                setbf.append(propertName.substring(1));
                try {
                    Method getMethodtarget = target.getClass().getMethod(getbf.toString());
                    Method getMethodactual = actual.getClass().getMethod(getbf.toString());
                    Method setMethodassess = assess.getClass().getMethod(setbf.toString(),item.getType());

                    double difference =  (double)getMethodactual.invoke(actual) -  (double)getMethodtarget.invoke(target);
                      if(dif!=null){
                          if(difference>0){
                              dif.put(propertName,"合理");
                          }else {
                              dif.put(propertName,"不合理");
                          }
                      }
                    setMethodassess.invoke(assess,Math.round(difference*100)/100);

                } catch (NoSuchMethodException e) {
                    log.error("没有找到相关get/set方法!");
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }
在这里插入代码片
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java中的反射机制可以实现给实体类添加属性,但是这个操作并不是很常见,也不建议这么做。因为Java反射机制是基于类的,而类是静态的,如果在运行时给类添加属性,可能会导致一些不可预测的问题。如果您需要动态地添加属性,可以考虑使用Map集合或者其他动态容器来存储属性值。如果您坚持要使用反射机制给实体类添加属性,可以通过以下步骤实现: 1. 获取实体类的Class对象 2. 获取Field数组,即实体类的所有属性 3. 创建新的Field对象,包括属性的名称、类型、修饰符等 4. 将新的Field对象添加到Field数组中 5. 使用反射机制设置该属性的值 下面是一个简单的示例代码: ``` public class ReflectTest { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { // 获取实体类的Class对象 Class clazz = User.class; // 获取Field数组 Field[] fields = clazz.getDeclaredFields(); // 创建新的Field对象 Field newField = new Field("newField", String.class, Modifier.PRIVATE); // 将新的Field对象添加到Field数组中 Field[] newFields = Arrays.copyOf(fields, fields.length + 1); newFields[fields.length] = newField; // 使用反射机制设置该属性的值 User user = new User(); newField.setAccessible(true); newField.set(user, "newFieldValue"); // 验证属性值是否设置成功 System.out.println(user.getNewField()); } } class User { private String name; private int age; // 新添加的属性 private String newField; // getter和setter方法 // ... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dylan95

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

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

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

打赏作者

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

抵扣说明:

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

余额充值