如何检查java中是否已调用函数?

时间:2013-04-28 09:11:21

标签: java android

我在Android Java项目中调用过两次方法,但我想只调用一次。当我第二次调用该方法时,我想检查该方法是否已被调用。代码是这样的:

class SomeClass {
    //called with certain condition
    private void a(){
         c(); //first call
    }

    private void b() {
         c(); //second call,check here whether function is invoked already or not,if invoked not invoke here or vice-versa
    }

    //called with certain condition
    private void c() {

    }
}

6 个答案:

答案 0 :(得分:4)

您必须使用布尔值(或计数器)来记录该方法是否已被调用。但是你如何做到这一点取决于正是你想要计算/限制的东西。

以下假定您使用计数器:

  • 如果要计算所有上下文中对方法的所有调用:

     private static int nos_calls;
    
     public void function c() {
         nos_calls += 1;
         // do the call
     }
    
  • 如果您只想计算给定对象的方法调用,那么:

     private int nos_calls;
    
     public void function c() {
         nos_calls += 1;
         // do the call
     }
    
  • 如果您希望阻止多次调用该方法:

     private int nos_calls;
    
     public void function c() {
         if (nos_calls++ == 0) {
             // do the call
         }
     }
    
  • 如果可以从不同的线程调用该方法,那么您需要以正确同步的方式进行计数; e.g。

     private AtomicInteger nos_calls = new AtomicInteger();
    
     public void function c() {
         if (nos_calls.incrementAndGet() == 1) {
             // do the call
         }
     }
    
  • 等等。

答案 1 :(得分:1)

您可以这样做:

class A{
    static boolean calledBefore = false;
    public void a(){
    ....
         c();
    }
    public void b(){
    ....
         c();
    }
    public void c(){

         if(!calledBefore){
             //This will be executed if c() is not called before
             //Do magic here

             calledBefore = true;
         }
    }
}
如果您想拥有多个A类实例并且允许每个实例调用calledBefore一次,那么

c()应该是非静态的。

答案 2 :(得分:1)

如果要在程序的整个运行时只运行一次,请使用类静态变量。如果要为每个对象运行一次,请添加一个对象成员变量

class RunOnce {
     private static boolean methodAHasRunOnce = false;
     private boolean methodBHasRun = false;

     public void methodA() {
         if(RunOnce.methodAHasRunOnce) { return; }
         System.out.println("Hello from methodA!");
         RunOnce.methodAHasRunOnce = true;
     }

     public void methodB() {
        if(this.methodBHasRun) { return; }
         System.out.println("Hello from methodB!");
         this.methodBHasRun = true;
     }
}

现在运行:

RunOnce one = new RunOnce();
RunOnce two = new RunOnce();
one.methodA();  // Output: Hello from methodA!
one.methodB();  // Output: Hello from methodB!

one.methodA();  // No output
one.methodB();  // No output

two.methodA();  // No output
two.methodB();  // Output: Hello from methodB!

two.methodA();  // No output
two.methodB();  // No output

答案 3 :(得分:1)

我在这里看到2个解决方案:

  1. 通过条件检查
  2. 执行此操作
    public Clazz {
        //private static boolean check = false; // if you want your method to be run once per class
        private boolean check = false; // if you want your method to be run once per class instance
    
        public void c() {
            if(check) {
                return;
            }
            check = true;
            ....
        }
    

    1. 通过拦截方法调用(例如Java动态代理,javassist,asm等)或使用AOP来实现此目的
    2. 但你必须有一个接口:

      public class TestInvocationHandler implements InvocationHandler {
      
          //private static boolean check = false;
          private boolean check = false;
      
          private Object yourObject;
      
          public TestInvocationHandler(Object object) {
              yourObject = object;
          }
      
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) 
              throws Throwable {
              if(check) {
                  return null; // or whatever you need
              }
              check = true;
              return method.invoke(yourObject, args);
          }
      }
      

      然后你会像这样创建你的对象:

      ObjectInterface i = (ObjectInterface) Proxy.newProxyInstance(ObjectInterface.class.getClassLoader(),
                             new Class<?>[] {ObjectInterface .class},
                             new TestInvocationHandler(new MyImplementingClass()));
      

答案 4 :(得分:0)

您可以向包含在函数中修改的函数的类中添加静态字段(例如,仅对其进行修改)以跟踪调用。

答案 5 :(得分:0)

方面将是这个问题的一般解决方案。我绝对不是一个专家(这个例子还没有经过测试),但它会像:

@Aspect
public class CallOnlyOnceAspect {

  @Pointcut("call(* methodThatShouldBeInvokedOnlyOnce(..))")
  void methodThatShouldBeInvokedOnlyOnce() {}

  @Around("methodThatShouldBeInvokedOnlyOnce()")
  public Object preventMultipleCalls(ProceedingJoinPoint thisJoinPoint) {
    // You need to implement this method for your particular methods/counters
    if (hasAlreadyExecuted(thisJoinPoint)) {
      return null;
      // or equivalent return value,
      // e.g. you may have cached the previous return value
    }
    Object result = thisJoinPoint.proceed();
    // Maybe cache result against thisJoinPoint
    return result;
  }

}

在这些地方可以找到更多细节: