美文网首页
Java 反射机制

Java 反射机制

作者: AD刘涛 | 来源:发表于2020-04-21 22:38 被阅读0次

    前言

    在本文中,我们将探讨java反射,它允许我们检查或/修改classes,接口,字段和方法的运行时属性。当我们在编译时不知道它们的names时,这特别有用。此外,我们可以使用反射实例化新对象、方法调用和获取或设置字段值。

    构建项目

    要使用java反射,我们不需要包含任何特殊的jar、任何特殊的配置或Maven依赖。出于这样的原因,JDK附带了一组类,这些类位于java.lang.reflect包中。因此,我们需要在我们的代码中导入下面的包

    import java.lang.reflect.*;
    

    要访问实例的类、方法和字段信息,我们需要调用getClass方法,它将返回对象运行时的类,返回的类对象提供了访问类信息的方法。

    案例

    首先,我们将看一个非常基本的案例。它在运行时检查一个简单java对象的字段。

    让我们创建一个简单的Person类,这个类只有nameage字段,且没有任何方法。以下就是Person类。

    public class Person {
        private String name;
        private int age;
    }
    

    现在,我们将使用java反射来探索这个类的所有字段名。为了展示反射的力量,我们将构造一个Person对象并使用object作为引用类型。

    @Test
    public void givenObject_whenGetsFieldNamesAtRuntime_thenCorrect() {
        Object person = new Person();
        Field[] fields = person.getClass().getDeclaredFields();
     
        List<String> actualFieldNames = getFieldNames(fields);
     
        assertTrue(Arrays.asList("name", "age")
          .containsAll(actualFieldNames));
    }
    

    这个测试向我们展示了我们能够从person对象中获得一个字段对象的数组,即使对该对象的引用是该对象的父类。

    在上面的例子中,我们只对那些字段名感兴趣,但是还有更多的事情可以做,我们将在后面的小节中看到更多的例子。

    注意我们是如何使用helper方法来提取实际的字段名的,这是非常基本的代码:

    private static List<String> getFieldNames(Field[] fields) {
        List<String> fieldNames = new ArrayList<>();
        for (Field field : fields)
          fieldNames.add(field.getName());
        return fieldNames;
    }
    

    使用Java反射的案例

    在继续介绍java反射的不同特性之前,我们将讨论它的一些常见用法。Java反射是非常强大的,在很多方面都非常方便。

    例如,在许多情况下,我们对数据库表有一个命名约定。我们可以选择通过在表名前面加上tbl来增加一致性,这样带有学生数据的表就称为tbl_student_data

    在这种情况下,我们可以将保存学生数据的java对象命名为studentStudentData。然后使用CRUD范式,我们为每个操作提供一个入口点,这样创建操作只接收一个对象参数。然后我们使用反射来检索对象名和字段名。此时,我们可以将此数据映射到一个DB表,并将对象字段值赋值给适当的DB字段名。

    探索 Java Classes

    在本节中,我们将探讨java反射API中最基本的组件。如前所述,java类对象允许我们访问任何对象的内部细节。我们将检查内部细节,如对象的类名、它们的修饰符、字段、方法、实现的接口等。

    Getting Ready

    为了更好地理解reflection API,我们将创建一个抽象的Animal class,它实现了Eating接口。这个接口定义了常见动物对象的饮食行为。

    首先,这是Eating接口

    public interface Eating {
        String eats();
    }
    

    其次我们实现了Animal接口

    public abstract class Animal implements Eating {
     
        public static String CATEGORY = "domestic";
        private String name;
     
        protected abstract String getSound();
     
        // constructor, standard getters and setters omitted 
    }
    

    让我们来创建另一个叫做Locomotion的接口,它描述了动物是如何行动:

    public interface Locomotion {
        String getLocomotion();
    }
    

    现在我们将创建一个名为Goat的具体类,它继承了Animal并实现了Locomotion接口。因为Animal类实现了Eating,所以Goat也必须实现该接口的方法:

    public class Goat extends Animal implements Locomotion {
     
        @Override
        protected String getSound() {
            return "bleat";
        }
     
        @Override
        public String getLocomotion() {
            return "walks";
        }
     
        @Override
        public String eats() {
            return "grass";
        }
     
        // constructor omitted
    }
    

    从现在开始,我们将使用java反射来检查出现在上面的类和接口中的java对象的各个方面:

    Class Names

    让我们从类中获取对象的名称开始:

    @Test
    public void givenObject_whenGetsClassName_thenCorrect() {
        Object goat = new Goat("goat");
        Class<?> clazz = goat.getClass();
     
        assertEquals("Goat", clazz.getSimpleName());
        assertEquals("com.baeldung.reflection.Goat", clazz.getName());
        assertEquals("com.baeldung.reflection.Goat", clazz.getCanonicalName());
    }
    

    注意,类的getSimpleName方法将返回该对象类的基本名称。然后,其他两个方法返回包名。

    让我们看看,如果我们只知道它是完全限定的类名时,我们如何创建Goat类的对象:

    @Test
    public void givenClassName_whenCreatesObject_thenCorrect(){
        Class<?> clazz = Class.forName("com.baeldung.reflection.Goat");
     
        assertEquals("Goat", clazz.getSimpleName());
        assertEquals("com.baeldung.reflection.Goat", clazz.getName());
        assertEquals("com.baeldung.reflection.Goat", clazz.getCanonicalName()); 
    }
    

    注意,我们传递给静态方法forName的名称时应该包含包的信息,否则我们将得到一个ClassNotFoundException异常。

    参考链接1
    参考链接2
    原文出处

    相关文章

      网友评论

          本文标题:Java 反射机制

          本文链接:https://www.haomeiwen.com/subject/eklhdhtx.html