有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

编译器构造Java:检查编译时是否存在给定的方法名

我正在开发一个实用程序类来处理来自JavaSwing组件的操作; 我想知道是否有一种方法可以检查给定的方法名(将由反射访问)在编译时是否存在,如果不存在则显示编译器错误

--更新

好的,看来我还不清楚,让我们谈谈细节:

我有一个名为TomAction的类,用于简化项目中的简单操作声明。而不是像这样写:

class MyClass {

    public MyClass() {
    Icon icon = null; // putting null to simplify the example
    JButton btn = new JButton(new AbstractAction("Click to go!", icon) {
        public void actionPerformed(ActionEvent ev) {
        try {
            go();
        } catch (Exception e) {
            e.printStackTrace();
            String msg = "Fail to execute 'go' task.";
            JOptionPane.showMessageDialog(null, msg, "Fail", JOptionPane.ERROR_MESSAGE);
        }
        }
    });
    }

    private void go() {
    // do task
    }

}

。。我只是写:

class MyClass {

    public MyClass() {
    String msg = "Fail to execute 'go' task.";
    Icon icon = null; // putting null to simplify the example
    TomAction act = new TomAction("go", this, "Click to go!", msg, icon);
    JButton btn = new JButton(act);
    }

    private void go() {
    // do task
    }

}

。。程序也有同样的行为

问题是,如果我键入了一个错误的方法名作为TomAction的参数,我将在运行时看到它。我希望在编译时看到它。明白了吗?:)

顺便说一下,这门课做得很好,我只想做这个增强

--更新

研究注释方法


共 (6) 个答案

  1. # 1 楼答案

    通过反射,这是可能的:

            Object o = object;
            try {
                Method m = o.getClass().getMethod("methodName");
                m.invoke(o);
            } catch (NoSuchMethodException e) {
                //Method is not available
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
    
  2. # 2 楼答案

    听起来好像您想建立一个契约,必须实现一个特定的方法

    在Java中,通常通过接口执行此操作:

    public interface Frobnicator {
      public void frobnicate();
    }
    

    然后,在其他代码中,您只需要获得该类型的对象,这样编译器将验证该方法是否存在:

    public void frobnicateorize(Frobnicator forb) {
      frob.frobnicate();
    }
    

    这样,您甚至可以避免使用反射来调用该方法

    编辑关于更新:不,Java编译器不能静态检查这种代码。您可能需要编写自己的工具来为您进行检查

  3. # 3 楼答案

    我不知道用任何现有的软件可以做到这一点

    然而,假设方法名可以在编译时解析(在这种情况下,您似乎不太可能使用反射),您可以创建一个IDE插件来完成这项工作

  4. # 4 楼答案

    您可以使用注释而不是字符串文字来表示调用的操作,然后使用APT来验证该方法是否存在。APT由javac自动调用

    http://java.sun.com/javase/6/docs/technotes/tools/windows/javac.html#processing http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html http://java.sun.com/j2se/1.5.0/docs/guide/apt/mirror/overview-summary.html

    以您的示例为例,我建议如下设计—在代码中放置绑定注释,并在注释处理器中添加动作实例化代码。在这种情况下,操作必须是类成员,这无论如何都是一个好的实践。确保您使用图标和文本的资源包,从长远来看,您将省去很多痛苦:

    class MyClass {
        // the keys should be looked up from resource bundle
        @TomActionBinding("go", "text-key", "msg-key", "icon-key");
        Action act;
    
        public MyClass() {
           JButton btn = new JButton(act);
        }
    
        private void go() {
           // do task
        }
    
    }
    
  5. # 5 楼答案

    不,没有办法

  6. # 6 楼答案

    无法在编译时检查动态方法。然而,可能需要重新设计框架类以实现所需的功能。除了AbstractAction之外,TomAction类真正提供的唯一功能是错误处理和重命名actionPerformed方法的能力,而使用反射和丢失类型安全性的代价(很高,IMHO)

    我会这样做:

    public class TomAction extends AbstractAction {
    
        public static interface Command {
            // CommandException is implemented elsewhere
            public void execute() throws CommandException;
        }
    
        private Command cmd;
        // other members omitted for brevity
    
        public TomAction(Command cmd, String name, String failMsg, Icon icon) {
            super(name, icon);
            this.cmd = cmd;
            this.failMsg = failMsg;
        }
    
        public void actionPerformed(ActionEvent e) {
            try {
                cmd.execute();
            }
            catch (CommandException e) {
                // handle failure
            }
        }
    
        // remaining implementation
    }
    

    然后使用它:

    TomAction.Command goCmd = new TomAction.Command() {
        public void execute() throws CommandException {
            go();
        }
    };
    
    TomAction act = new TomAction(goCmd, "Click to go!", msg, icon);
    JButton btn = new JButton(act);
    

    它比您现有的实现要详细一点,但它提供了所需的编译时类型安全性