Метод ввода отладки IntelliJ IDEA несколько раз

При отладке следующего кода:

public class MyProxy {
    public static void main(String[] args){

        Consumer f = (Consumer) Proxy.newProxyInstance(
                Consumer.class.getClassLoader(),
                new Class[] { Consumer.class },
                new Handler(new ConsumerImpl())
        );

        f.consume("Hello");   // set breakpoint here
        System.out.println("done");
    }
}

interface Consumer {
    void consume(String s);
}

class ConsumerImpl implements Consumer {
    public void consume(String s) {
        System.out.println(s);
    }
}

class Handler implements InvocationHandler {
    private final Consumer original;
    public Handler(Consumer original) {
        this.original = original;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
        System.out.println("BEFORE");
        method.invoke(original, args);
        System.out.println("AFTER");
        return null;
    }
}

Результат:

BEFORE
AFTER
BEFORE
AFTER
BEFORE
BEFORE
AFTER
Hello
BEFORE
AFTER
AFTER
BEFORE
AFTER
BEFORE
AFTER
BEFORE
AFTER
BEFORE
AFTER
done
BEFORE
AFTER

Когда отладчик останавливается на строке точки останова, в выводе уже есть две строки, когда я перехожу к методу invoke, вывод выглядит так, как показано. Как будто отладчик вводит метод invoke на каждом моем шаге. Потому что, если я не перейду к методу, вывод будет:

BEFORE
AFTER
BEFORE
Hello
AFTER
BEFORE
AFTER
done
BEFORE
AFTER

Если я запускаю код, результат будет таким, как ожидалось.

BEFORE
Hello
AFTER
done

Это ошибка отладчика или я что-то не так делаю?

Оболочка: Windows 64, Intellij IDEA, JDK8


person matrix    schedule 23.03.2017    source источник


Ответы (1)


Это не ошибка в IDEA. если вы попытаетесь отладить это без каких-либо точек останова, вы можете получить тот же результат, что и ожидали. Но если вы поставите точку останова, IDEA попытается вызвать метод toString(), а затем метод hashCode() переменных, которые она может оценить.

в конечном итоге для всех методов он вызовет вашу реализацию InvocationHandler (не только для метода «потребить», вы можете напечатать method.getName(), чтобы убедиться в этом в реализации обработчика вызова).

person hunter    schedule 23.03.2017
comment
Правильно ли я понимаю: 1. при отладке при каждом моем движении отладчик будет переоценивать каждую переменную (вызывая toString() и hashCode()) в области видимости, чтобы обновить ее значение. 2. При пошаговом методе invoke оценивается this, вызывая тот же эффект, что и при оценке f в main(). - person matrix; 24.03.2017
comment
Я тестировал с method.getName() , для оценки вызывается только toString(), а не hashCode(). - person matrix; 24.03.2017
comment
да, в вашем случае это только метод toString(). первый абзац моего ответа просто касается общего случая, если это обычный класс (если вы не переопределили toString()), то метод hashCode будет выполняться через метод toString(). я думаю, что мой ответ несколько неясен о методе hasCode. - person hunter; 24.03.2017
comment
@hunter, не могли бы вы объяснить это более подробно, приведя подробный пример. В моем контроллере Grails у меня есть метод show(id), который вызывается 3 раза в режиме отладки, когда у моего метода есть точка останова. И без точки останова он отлично работает в режиме отладки. Я хочу знать его причину. - person Bharti Rawat; 03.02.2020