Для справки я создаю пример, используя ваш подход; в то время как он работает, он также предлагает проблему фокуса в другом месте вашего кода. Привязки клавиш избегают этого, как показано здесь здесь .
Приложение: Вот ссылка на мое рабочее ключевое слово.
private static class TestPanel extends JPanel {
private static final String LEFT = "Left";
private Action left = new AbstractAction(LEFT) {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(LEFT);
}
};
private static final String RIGHT = "Right";
private Action right = new AbstractAction(RIGHT) {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(RIGHT);
}
};
public TestPanel() {
this.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), LEFT);
this.getActionMap().put(LEFT, left);
this.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), RIGHT);
this.getActionMap().put(RIGHT, right);
}
}
Оригинал SSCCE :
import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* @see https://stackoverflow.com/a/16531380/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TestPanel());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class TestPanel extends JPanel implements KeyListener {
public TestPanel() {
this.addKeyListener(this);
this.setFocusable(true);
this.requestFocusInWindow();
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
System.out.println("Left");
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new Test().display();
}
});
}
}
If you want to be absolutely certain, then compile it both ways and decompile it and compare. I did this with the following source:
public void test() {
Map<String, String> myMap = new HashMap<String, String>();
for (String key : myMap.keySet()) {
System.out.println(key);
System.out.println(myMap.get(key));
}
Set<String> keySet = myMap.keySet();
for (String key : keySet) {
System.out.println(key);
System.out.println(myMap.get(key));
}
}
and when I decompiled the class file with Jad, I get:
public void test()
{
Map myMap = new HashMap();
String key;
for(Iterator iterator = myMap.keySet().iterator(); iterator.hasNext(); System.out.println((String)myMap.get(key)))
{
key = (String)iterator.next();
System.out.println(key);
}
Set keySet = myMap.keySet();
String key;
for(Iterator iterator1 = keySet.iterator(); iterator1.hasNext(); System.out.println((String)myMap.get(key)))
{
key = (String)iterator1.next();
System.out.println(key);
}
}
So there's your answer. It is called once with either for-loop form.
keySet()
вызывается только один раз. «Расширенный цикл for» основан на интерфейсе Iterable
, который он использует для получения Iterator
, который затем используется для цикла. Даже невозможно перебрать Set
любым другим способом, так как нет индекса или чего-либо еще, с помощью чего вы могли бы получить отдельные элементы.
Однако, что вы действительно должны сделать, так это полностью отказаться от такого рода проблем микрооптимизации - если у вас когда-либо возникают реальные проблемы с производительностью, вероятность составляет около 99%, что вы никогда не задумывались сами по себе.
Звонят только один раз. На самом деле для решения этой задачи используется итератор.
Кроме того, в вашем случае, я думаю, вам следует использовать
for (Map.Entry<String, String> entry : myMap.entrySet())
{
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
, чтобы каждый раз избегать поиска на карте.
Я считаю, что компилятор оптимизирован для запуска только один раз для каждой записи цикла.
Ответ находится в Спецификации языка Java, декомпилировать не нужно :) Это то, что мы можем прочитать о расширенном операторе for :
Расширенный оператор for имеет форму :
EnhancedForStatement: for (VariableModifiersopt Type Identifier: Expression) Statement
Выражение должно иметь тип
Iterable
, иначе он должен иметь тип массива (§10.1), иначе возникает ошибка времени компиляции .Объем локальной переменной, объявленной в части FormalParameter расширенного оператора
for
(§14.14), является содержащимся в нем операторомЗначение расширенного оператора
для
дается путем перевода в базовый оператордля
.Если тип
Выражения
является подтипомIterable
, то пустьI
будет типом выражение Выражение.итератор ()
. Расширенный операторfor
эквивалентен базовому операторуfor
формы :for (I #i = Expression.iterator ( ); # i.hasNext ();) { Идентификатор типа VariableModifiersopt = #i.next (); Оператор }
Где
#i
- генерируемый компилятором идентификатор , отличный от любого { {1}} другие идентификаторы (генерируемые компилятором или иначе), которые находятся в области действия (§6.3) в точке, где происходит расширенный оператор for .В противном случае Выражение обязательно имеет тип массива,
T []
. ПустьL1 ... Lm
будет (возможно, пустой) последовательностью меток, непосредственно предшествующей расширенному операторудля
. Тогда значение расширенного оператора for задается следующим основным операторомfor
:T [] a = Expression; {{ 1}} L1: L2: ... Lm: for (int i = 0; i
Где a и i - генерируемые компилятором идентификаторы , отличные от любых {{ 1}} другие идентификаторы (генерируемые компилятором или иначе), которые находятся в области видимости в точке , где происходит расширенный оператор for .
В вашем случае myMap.keySet ()
возвращает подтип Iterable
, поэтому ваш расширенный оператор for
эквивалентен следующему базовому для Оператор
:
for (Iterator<String> iterator = myMap.keySet().iterator(); iterator.hasNext();) {
String key = iterator.next();
System.out.println(key);
System.out.println(myMap.get(key));
}
И myMap.keySet ()
, таким образом, вызывается только один раз.