【问题标题】:Using reflection based static invocation instead of interfaces使用基于反射的静态调用而不是接口
【发布时间】:2014-03-16 07:44:35
【问题描述】:

我的问题是 Java 中的一般设计问题。在典型的基于控制器的设计(比如 MVC)中,控制器通常创建动作实例并调用从接口实现的方法(比如 Action 接口的 execute())。

为什么我们需要创建不必要的对象,为什么不使用静态调用并消除实现接口的需要?

就像下面的例子。就像每个 Java 程序都应该有一个 main() 方法一样,每个动作方法都应该有一个 execute()

class MyActionClass {
    public static void execute() {
        System.out.println("Hello from execute()!!");
    }
}

public class StaticTest {

    /**
     * @param args
     * @throws ClassNotFoundException
     * @throws SecurityException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static void main(String[] args) throws ClassNotFoundException,
                        NoSuchMethodException, SecurityException, IllegalAccessException,
                        IllegalArgumentException, InvocationTargetException {
        Class<?> clazz = Class.forName("MyActionClass");
        Method method = clazz.getMethod("execute");
        method.invoke(null);
    }

}

【问题讨论】:

  • 反射也实例化了对象。
  • Radiodef 确实如此,我想我在自我审议后找到了这个问题的答案。可能这就是我们在 Spring 框架中使用“单例”的原因。

标签: java model-view-controller interface static-methods


【解决方案1】:

因为反射 API 比使用反射时的方法调用慢得多,所以编译器无法进行任何优化,因为它无法真正了解您在做什么。

通过拥有一个接口和多个实现它的具体类,我们可以获得多态行为的优势。在等式中添加Factory pattern,您可以直接使用您的接口,而无需知道您正在调用哪个具体的类方法。额外的好处是编译器将能够优化您的代码,使其运行速度比使用反射 API 快得多。

从 Java 8 开始,我们可以在接口中实现静态和实例方法。这是一个演示:

public class InterfaceDemo
{
  public static void main(String... args)
  {
    XYZ.executeStatic("Hello");

    XYZ object = new Implementer();
    object.executeInstance("Message");
  }
}

interface XYZ
{
  static void executeStatic(String message)
  {
    System.out.println("Static: " + message);
  }

  default void executeInstance(String message)
  {
    System.out.println("Instance: " + message);
  }
}

class Implementer implements XYZ {}

然后是功能接口,如:

@FunctionalInterface
public interface Returnable<T>
{
  public T value();
}

这允许使用 lambda 表达式创建不同的实现,例如:

Returnable<Integer> integerReturnable = () -> 42;
Returnable<String> stringReturnable = () -> "Hello";

并像这样使用:

System.out.println(integerReturnable.value()); // Prints 42
System.out.println(stringReturnable.value()); // Prints Hello

顺便说一句,如果需要创建很多对象,我们使用Object Pool pattern 或类似的东西,如果有很多类似的对象,我们使用Flyweight Pattern 以在保持速度的同时尽量减少内存使用.

【讨论】:

  • 同意我们在实例化大量对象时需要工厂模式。但是我这里的问题是这些动作类通常没有本地存储,消费者想要做的只是执行一些动作,为什么消费者在可以利用静态调用的情况下需要实例化对象?我相信所有这些框架都已经使用反射来实例化适当的动作类,所以不存在反射慢的问题。
  • 那么您特别在谈论什么框架?因为在 MVC 架构中,模型和视图不是由反射创建的,而是由对象实例化创建的,然后使用传统的方法调用来使用它们。框架可以使用反射来实例化对象上的方法,但是还有许多其他更简单、更快的方法来处理这种情况。与直接方法调用和对象实例化相比,反射速度较慢,这就是为什么普遍共识不偏向于使用它的原因。反射 API 有其优势,但在这种情况下并非特别如此。
  • 对我的问题的同意答案是 Flyweight,昨天晚上我没有想到八点,正如我向 Radiodef 指出的那样。
  • 嗯,我看不出您在哪里向 Radiodef 提到您不是在谈论 Java 8,但话说回来,很难得到您最初真正要问的内容。 :D 所以我最终甚至告诉了你问题的周边方面,以达到靶心。很高兴您同意我回答的一部分作为您问题的答案,尽管我回答的其他部分在他们方面很有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多