【问题标题】:Invoke Superclass method via reflection通过反射调用超类方法
【发布时间】:2016-01-29 16:12:07
【问题描述】:

我正在使用基于 Eclipse 的软件,该软件允许创建应用程序并自动提供默认用户界面。 我正在尝试修改此界面(例如更改按钮图标、前景色等),但不幸的是我无法修改源代码,所以我试图通过 java 反射来实现。 借助 JD-GUI 之类的软件,我无论如何都可以查看已编译的 jar 文件,但我不想修改和重新编译 jar。 问题是这个接口是通过自定义类构建的,这些类扩展了 Swing 组件,并且查看 jar 文件,我发现实现了一些烦人的技巧。举个例子:

final class MyToggleButton extends JToggleButton{
    MyToggleButton (ImageIcon defaultIcon){
        super.setIcon(defaultIcon);
    }
    @Override
    public void setIcon(Icon icon){}
}

对于以这种方式构建的类,如果我在 MyToggleButton 的实例上调用 setIcon() 方法,它不会生效,因为 override 方法内部没有代码(我认为)。所以我无法更改他们在特定按钮上默认设置的图标。

有人知道解决这个问题的方法吗? 提前感谢您的帮助。

附:我不是javer,但我对反射很熟悉。

【问题讨论】:

    标签: java swing user-interface reflection


    【解决方案1】:

    这是不可能的。只有通过特殊的字节码指令 (invokespecial) 才能调用超类方法并绕过类中的覆盖,该指令只能在覆盖该方法的类内部使用。没有办法通过反射来执行这样的调用。

    【讨论】:

    • yole,感谢您的回复。只是为了确定我明白了这一点,这是否意味着由于上述源代码,无法更改 JToggleButton 的图标?
    • 更改图标最简单的方法是解压缩 .jar 文件,更改包含图标的文件并重新打包。这比反编译和重新编译类要容易得多,而且比您可能想出的任何反射技巧都可靠得多。
    【解决方案2】:

    正如其他人所提到的,如果超类的方法已被覆盖,则无法通过反射调用它。如果可能的话,您应该在这样做之前寻找另一种解决问题的方法,例如yole's suggestion,因为这既难以阅读又难以维护(例如,如果setIcon() 方法实现,它很容易意外中断更改或 default_icon 字段更改名称)。

    但是,如果您绝对想要并且必须您可以根据第 1710 行的 setIcon() here 的源执行类似的操作来“模仿”方法调用。

    public static void setButtonIcon(MyToggleButton button, Icon icon) {
          if (button.getIcon() == icon)
                return;
    
          Icon old = button.getIcon();
    
          // Use reflection to set the icon field
          try {
                Field f = AbstractButton.class.getDeclaredField("default_icon");
                f.setAccessible(true);
                f.set(button, icon);
          } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
                e.printStackTrace();
                return;
          }
    
          button.firePropertyChange(AbstractButton.ICON_CHANGED_PROPERTY, old, icon);
          button.revalidate();
          button.repaint();
    }
    

    Reflection reference

    【讨论】:

      【解决方案3】:

      您不能调用方法的超类版本。但是,通过反思,您可能可以执行相同的逻辑。例如,通过反射,您可以将您的图标分配给JToggleButton 中的字段,并调用将属性更改事件分派给注册的侦听器的方法等。

      基本上,您应该查看JToggleButton 的源代码(或定义该方法的任何位置),并使用反射在其原始setIcon() 方法中重现代码。不容易、漂亮或可维护,但它会起作用。

      【讨论】:

      • 非常感谢您的帮助。不幸的是,这对我来说似乎有点复杂,因为我不是程序员。如果不麻烦的话,您能否提供一个使用我上面发布的类所需代码的示例?
      猜你喜欢
      • 1970-01-01
      • 2019-08-07
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-11
      相关资源
      最近更新 更多