ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java反射初相识

2020-12-05 16:32:15  阅读:221  来源: 互联网

标签:反射 Java student setName 相识 name Student Class String


什么是反射

在了解反射之前先来看下面的Demo,首先定义了一个简单的学生类,其中有两个成员变量,分别是姓名:name 年龄:age 还有一个方法: void study(String val);然后通过两种方式进行调用.

public class Student {
    public String name;
    private int age;
    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 void study(String val){
        System.out.println(name + "喜欢学习" + val);;
    }
}

调用方式一

//初始化对象
Student student = new Student();
//为变量赋值
student.setName("小舍");
//为变量赋值
student.study("Java");
//输出结果为:小舍喜欢学习Java

调用方式二

//获取Student的Class
Class student = Class.forName("com.demo.Student");
//通过Class创建Student对象
Object instance = student.newInstance();
//获取setName方法给对象属性赋值
//获取setName方法,setName有一个字符串的参数
Method setName = student.getMethod("setName", String.class);
//执行setName
//相当于instance.setName"小舍"
setName.invoke(instance, "小舍");
Method study = student.getMethod("study", String.class);
study.invoke(instance,"Java");
//输出结果为:小舍喜欢学习Java

运行后可以发现这两种调用方式的执行结果一致,方式一想必大家都不陌生,开发中经常用到,而方式二便是所谓的反射了.

这两种方式有什么区别呢?

在方式一中,已经确定了初始化的对象是什么,然后可以通过new关键字来创建对象,再通过对象调用方法;而在方式二中,则是在运行时,通过输入的字符串(com.demo.Student)才确认要运行的类什么,调用方法时,则通过类中的方法名和参数类型来调用.

可以说反射就是在运行时,可以创建任意一个对象,并且可以操作其任意一个变量或者方法.

现在看看来源于百度百科的定义,还有什么疑问吗?

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。--- 百度百科

如何使用

使用反射大致分为三个步骤

  1. 获取类的Class对象;
  2. 通过Class对象获取类的内容(构造方法,成员方法, 成员变量)
  3. 对获取的内容进行操作

1.获取Class对象

//1. 通过对象调用getClass方法获取。
Student stu0 = new Student();
Class stu0Class = stu0.getClass();
//2. 通过类的class属性获取。
Class stu1Class = Student.class;
//3. 通过Class的静态方法forName获取
Class stu2Class = Class.forName("com.demo.Student");

一个类只有一个Class类型的对象,无论怎么获取,获取的都是同一个Class

System.out.println(stu0Class == stu1Class);//true
System.out.println(stu0Class == stu2Class);//true
System.out.println(stu1Class == stu2Class);//true

2.通过Class对象获取类的内容

/**
 * T newInstance()创建对象
 */
Student student = (Student)stuClass.newInstance();
/**
 * Constructor getConstructor(Class... parameterTypes):获取空参构造方法
 */
Constructor constructor = stuClass.getConstructor();
/**
 *  Constructor[] getConstructors():获取所有的构造方法
 */
Constructor[] constructors = stuClass.getConstructors();
/**
 * Method[] getMethods():获取类中所有成员方法
 */
Method[] methods = stuClass.getMethods();
/**
 *  Method getMethod(String name, Class... parameterTypes):获取到的类中的指定的成员方法。 第一个参数是方法名, 第二个参数是该方法的参数列表。
 */
Method study = stuClass.getMethod("study", String.class);
/**
 * 反射获取set/get方法分别完成赋值和取值的操作
 */
Method setName = stuClass.getMethod("setName", String.class);
/**
 *  Object invoke(Object obj, Object... args):执行获取的方法 第一个参数是调用者对象,第二个对象表示调用方法时传递的实际参数
 */
setName.invoke(student,"小舍");
study.invoke(student,"Java");//小舍喜欢学习Java

/**
 *  Field getField(String name):获取成员变量, 只能获取到public权限的成员变量。
 */
Field nameField = stuClass.getField("name");//public java.lang.String com.demo.Student.name
String name = nameField.getName();//name
Field ageField = stuClass.getField("age");//java.lang.NoSuchFieldException: age(权限为 private)

3.对获取的内容进行操作

/**
 *  Object invoke(Object obj, Object... args):执行获取的方法 第一个参数是调用者对象,第二个对象表示调用方法时传递的实际参数
 */
setName.invoke(student,"小舍");
study.invoke(student,"Java");//小舍喜欢学习Java

存在的意义

通过反射,可以让程序创建和控制任何类的对象,无需提前硬编码目标类.例如,如果没有反射,每当我们构建对象时,都要同过new 关键字来创建对象,提前对对象进行编码,如果要改变对象,那么必须修改源代码,并重新编译.如果使用反射,可以将类(com.demo.Student)写在配置文件中,这样可以通过修改参数,来改变实例化对象.

反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力,是构建框架技术的基础所在.框架就是抽取重复的代码,提高编码效率,如果提前硬编码目标类,那如何抽取重复代码呢?

判断对象成员变量是否为空

    public static void main(String[] args) throws IllegalAccessException {
        Student student = new Student();
        student.setAge(18);
        student.setName("小舍");
        String[] fieldArray = {"name", "age"};
        List<String> fieldList = Arrays.asList(fieldArray);
        if (checkObjectFiledIsNull(student,fieldList)){
            System.out.println("参数不得为空");
        }
    }

	/**
     * 校验对象字段是否为空
     *
     * @param object    对象
     * @param fieldList	需要判空的变量名
     * @return 为空 返回true
     * @throws IllegalAccessException
     */
    public static boolean checkObjectFiledIsNull(Object object, List<String> fieldList) throws IllegalAccessException {
        if (object == null) {
            return true;
        }
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            if (fieldList.contains(field.getName())) {
                Object obj = field.get(object);
                if (StringUtils.isEmpty(obj)) {
                    return true;
                }
            }
        }
        return false;
    }

(1)student.setAge(18);

(2)student.setName("小舍");

注意:去掉(1)并不会打印"参数不得为空",而去掉(2)则会打印,是因为int变量的默认初始值为0

标签:反射,Java,student,setName,相识,name,Student,Class,String
来源: https://www.cnblogs.com/JavaUrl/p/14090120.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有