看一下这个奇怪的问题:




我在对字段res1的所有访问上都有一个断点
Res1分配了f的值,即“ bar”
Res1现在是“栏”
在下一个中断处,res1突然是null


为什么这不可能呢?


由于res1的断点,我可以看到它根本不应该更改
而且不能,因为我没有在赋值和assertEquals之间显式更改它,并且此代码在单个JUnit线程中运行。
没有其他名为res1的字段或变量。


可能是什么?我假设这不是JVM中的错误,但谁知道。



正如Jon Skeet所说,问题在于实例不同。这是由以下奇怪的反射问题引起的:

public class ServiceObject {

    private static final Map<Class<?>, Map<String, Operation>> opsByClass =
        new ConcurrentHashMap<Class<?>, Map<String,Operation>>();

    private final Object target;
    private final Map<String, Operation> myClassOps;

    private class Operation {
        private final Method method;
        public Operation(Method met) {
            this.method = met;
            method.setAccessible(true);
        }
        public void execute(Map<String,?> args, Responder responder, Object context, boolean coerce) {
            ...
            method.invoke(target, mArgs);
        }
    }

    public ServiceObject(Object target) {
        Class<?> myClass = target.getClass();
        Map<String, Operation> op = opsByClass.get(myClass);
        if (op == null) {
            op = new HashMap<String, Operation>();
            for (Method meth : myClass.getMethods()) {
                ...
                op.put(opName, new Operation(meth));
            }
            opsByClass.put(myClass, op);
        }
        this.target = target;
        this.myClassOps = op;
    }

    public void execute(String opName) {
        Operation op = myClassOps.get(opName);
        ...
        op.execute(args, responder, context, coerce);
    }
}

// Foo is equivalent to the class that contains <res1> above
class Foo {

    @ServiceOperation
    public void bar() {
        // breakpoint here
    }

}


运行测试时会发生什么:

a = new Foo();
b = new Foo();
svc = new ServiceObject(a);
svc.execute("bar", ...); // inside Foo.bar() <this> will be <a>
svc = new ServiceObject(b);
svc.execute("bar", ...); // inside Foo.bar() <this> will still be <a>, but should be <b>

最佳答案

猜测:您在断言阶段正在查看的类实例与在将其设置为“ bar”时的实例不同。

但是,如果不看其余的代码,很难说出来。

编辑:问题是您的opsByClass缓存将包含一个操作,该操作隐式具有关联的ServiceObject。因此,当使用ServiceObject创建第一个Foo时,它将缓存与ServiceObject的第一个实例关联的Operation实例。当您在svc.execute的第二个实例上调用ServiceObject时,它将在映射中查找操作,并找到与第一个实例相关联的Operation ...这可能不是您想要的。

09-06 06:40