从匿名内部类设置外部变量

TC1*_*TC1 52 java anonymous-class

有没有办法从Java中的匿名内部类访问调用者范围的变量?

以下是了解我需要的示例代码:

public Long getNumber(final String type, final String refNumber, final Long year) throws ServiceException {
    Long result = null;
    try {
        Session session = PersistenceHelper.getSession();
        session.doWork(new Work() {
                public void execute(Connection conn) throws SQLException {
                    CallableStatement st = conn.prepareCall("{ CALL PACKAGE.procedure(?, ?, ?, ?) }");
                    st.setString(1, type);
                    st.setString(2, refNumber);
                    st.setLong(3, year);
                    st.registerOutParameter(4, OracleTypes.NUMBER);
                    st.execute();
                    result = st.getLong(4) ;
                }
            });
    } catch (Exception e) {
        log.error(e);
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

代码位于DAO服务类中.显然它不会编译,因为它要求result是final,如果是 - 它不会编译,因为我尝试修改最终的var.我被JDK5绑定了.除了doWork()完全放弃之外,有没有办法从内部设置结果值doWork()

Lou*_*nco 62

Java不知道doWork将是同步的,并且结果所在的堆栈帧仍然存在.你需要改变堆栈中没有的东西.

我认为这会奏效

 final Long[] result = new Long[1];
Run Code Online (Sandbox Code Playgroud)

然后

 result[0] = st.getLong(4);
Run Code Online (Sandbox Code Playgroud)

execute().最后,你需要return result[0];

  • 这太脏了,我现在想洗个澡,因为我看了:) (59认同)
  • 我只是在我的键盘上呕吐,然后出于懒惰而不想创建一个持有者类,我做到了这一点. (9认同)
  • 虽然这会起作用,但它有点丑陋.我想如果你想返回这样的值,你应该使用一个命名的内部类而不是一个匿名的内部类.这是'清洁'恕我直言. (5认同)
  • @chzbrgla洗完澡后,以下解决方案为我工作。公共静态最终AtomicLong RESULT = new AtomicLong(0); RESULT.set(st.getLong(4););` (2认同)

小智 15

这种情况在Java中出现很多,处理它的最简单方法是使用简单的值容器类.它与阵列方法的类型相同,但IMO更清晰.

public class ValContainer<T> {
    private T val;

    public ValContainer() {
    }

    public ValContainer(T v) {
        this.val = v;
    }

    public T getVal() {
        return val;
    }

    public void setVal(T val) {
        this.val = val;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Aritra,很难找到像这样的东西的引用,但是我已经为14年代做了java,当你需要从一个方法获得一个返回值时(除了它的实际返回值)你必须传递一个对象,并让该对象具有您可以在返回时检查的属性.我的一小段代码只是一种通用的方式,比使用数组更简洁,或者只是用于获取"out参数"的专用类. (3认同)

SJu*_*n76 8

如果包含的类是MyClass - >

MyClass.this.variable = value;
Run Code Online (Sandbox Code Playgroud)

不记得这是否适用于私有变量(我认为它会起作用).

仅适用于类的属性(类变量).不适用于方法局部变量.在JSE 7中,可能会有闭包来做这种事情.


Ode*_*eer 8

龙是不变的.如果使用可变类,持有long值,则可以更改该值.例如:

public class Main {

public static void main( String[] args ) throws Exception {
    Main a = new Main();
    System.out.println( a.getNumber() );
}

public void doWork( Work work ) {
    work.doWork();
}


public Long getNumber() {
    final LongHolder result = new LongHolder();
    doWork( new Work() {
        public void doWork() {
            result.value = 1L;
        }
    } );
    return result.value;
}

private static class LongHolder { 
    public Long value; 
}

private static abstract class Work {
    public abstract void doWork();
}

}
Run Code Online (Sandbox Code Playgroud)


Emm*_*uel 7

最简单(最简单)的方法是使用AtomicLongJava 1.5以来的可用方法

public Long getNumber(final String type, final String refNumber, final Long year) throws ServiceException {
   final AtomicLong result = new AtomicLong;
   try {
       Session session = PersistenceHelper.getSession();
       session.doWork(new Work() {
               public void execute(Connection conn) throws SQLException {
                   //...
                   result.set(4);
                   //...
               }
           });
   } catch (Exception e) {
       log.error(e);
   }
   return result.get;
}
Run Code Online (Sandbox Code Playgroud)

在还有其他AtomicXXX变体可java.util.concurrent.atomic包:AtomicIntegerAtomicBooleanAtomicReference<V> (for your POJOs)