首页 文章

如何使用反射/内省来维护程序?

提问于
浏览
0

当我使用内省时,我有以纯文本编写的类,方法和属性名称 . 就像在这个简短的演示:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;



public class SO {
public static void main(String[] args)
        throws NoSuchMethodException, ClassNotFoundException,
        InvocationTargetException, IllegalAccessException, InstantiationException,    NoSuchFieldException {

    final Class<?> myClass = Class.forName("myClass");
    final Constructor<?> defaultConstructor = myClass.getDeclaredConstructor();
    final Object myInstance = defaultConstructor.newInstance();
    final Method myMethod = myClass.getDeclaredMethod("myMethod");
    myMethod.invoke(myInstance, "arg1", 3, true);
    final Field myFied = myClass.getDeclaredField("myFied");
    final Object value = myFied.get(myInstance);
}

}

由于没有对此代码进行编译检查,如果我的目标类/方法/字段/签名在代码库中发生了任何变化,它可能会在运行时中断 . 有时IDE可以在重构时提供帮助,但通常我们可能会错过更改并在运行时出现致命错误 .

你知道避免这种问题的方法吗?

注意:没有有用答案的任何'Avoid reflection whenever possible'都会得到-1 .
这不是一个威胁:我的问题不是'should I use introspection ?'而且我觉得答案纯粹是在污染这个问题 .

7 回答

  • 2

    编写自动化集成测试,使用 生产环境 中使用的实际配置文件并测试系统的完整路径 . 设置持续集成,以便在这些集成测试失败时立即通知您 .

    由于这些类型的错误只会在运行时出现,因此自动化测试是在受控环境中模拟运行时行为的方法 .

  • 3

    你知道如何避免这种问题吗?

    是 . 不要那么多使用反射/内省 . 非反射代码本质上不如其反射等效代码脆弱,并且更容易阅读并且显着更快 .

    我不知道任何IDE支持检查反射代码是否存在可能的运行时错误 . 事实上,在一般情况下,这是不可能的,因为它等同于停机问题 .


    要说清楚,我没有说你根本不应该使用反射 . 存在反射是最佳解决方案的问题 . 但是,如果您发现基于反射的代码的脆弱性是一个重要问题,那么您可能使用它太多了 .

  • 1

    我会尝试重构任何使用硬编码反射的代码来删除硬编码 . 例如,你可以重构:

    public Object getInstance() {
    
        return (Class.forName("myClass"));
    }
    

    如:

    public Object getInstance(Class<?> clazz) {
    
        return (clazz.newInstance());
    }
    

    这个例子显然是微不足道的,但重点是尝试使用变量来确定该类而不是硬编码 .

    更好的是,您可以对其进行注释,然后使用反射来获取带注释的元素,而不是对类,方法或字段名称进行硬编码 .

  • 4

    根据其他答案,尽可能避免反思 .

    但有时你不能(例如Spring MVC bean绑定,Wicket PropertyModels等) . 在这些情况下以及使用反射来记录(在get / set方法中)这些方法,我倾向于添加静态字符串,例如对于一个名为surname属性的bean

    public static final String PROPERTY_SURNAME = "surname"
    
    public String getSurname(...
    public void setSurname(...
    

    并在代码中使用 PROPERTY_SURNAME 而不是 "surname" 本身 . 它是开发人员改变get / set方法的暗示 .

  • 1

    当然 . 尽可能避免反射 . 由于反射的意图是围绕类型检查,因此在编译时没有其他可靠的方法来检查类型 . 如果您找到了针对特定案例的方法,则可以避免在这种情况下进行反思 .

  • 1

    你的例子很小,可以提供很多提示,但有时我会做一件事:

    编写一个Java接口,其中包含要调用的方法 . 使用该接口获取此接口的方法对象 . 然后使用它的名称和参数来查找您真正想要调用的方法 . 例如 . 每个接口一个方法,因此类名表示您想要的操作 .

    你的myClass不需要实现接口......

  • 2

    我会说“尝试使用Jython”,而不是说“不要使用反射” .

    http://onjava.com/pub/a/onjava/2002/03/27/jython.html?page=2

    请注意,那篇文章此时已相当陈旧;我只提供了它作为一个例子 . 例如,"Python coders rarely use simple get and set methods, preferring to access the variable directly."部分完全忽略了Python的 property() builtin(当时相当新的)的实用性,它允许透明的getter和setter使用,提供两全其美 . 但是,这种情况越来越严重,所以无论如何 .

    哦,对,你可能要看一个模块是http://www.jython.org/docs/library/inspect.html

相关问题