gui framework example create java swing dialog anonymous-function final

java - framework - Usando la matriz final de 1 elemento para la clase interna anónima



jdialog java example (4)

Me encontré con este truco para obtener un valor de una clase interna anónima a una variable que se declara en la clase externa. Funciona, pero se siente como un hack sucio:

private int showDialog() { final int[] myValue = new int[1]; JPanel panel = new JPanel(); final JDialog dialog = new JDialog(mainWindow, "Hit the button", true); dialog.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); JButton button = new JButton("Hit me!"); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { myValue[0] = 42; dialog.setVisible(false); } }); panel.add(button); dialog.add(panel); dialog.pack(); dialog.setVisible(true); return myValue[0]; }

(Sí, me doy cuenta de que este ejemplo podría reemplazarse con un simple JOptionPane , pero mis diálogos reales son mucho más complicados). La función interna insiste en que todas las variables con las que interactúa sean final , pero no puedo declarar myValue como final porque el la función interna necesita asignarle un valor. Declararlo como un conjunto de 1 elemento evita este problema, pero parece que podría ser un Bad Thing TM de alguna manera. Me pregunto si a.) Esto es una práctica común o b) hay problemas serios que podrían resultar de hacer esto.


Eso parece sucio Realmente no puedo hablar de lo "común" que es, y no sé si estás arriesgándote a la destrucción del mundo al hacerlo, pero si necesitaba algo como esto, preferiría morder la bala y escribir un clase interna completa (en lugar de la variedad anónima) para implementar ActionListener . De esta forma, puede hacer que afecte a los campos de su clase adjunta y llame a otros métodos en la clase adjunta, según sea necesario. Dependiendo de lo que estés haciendo exactamente, incluso valdrá la pena simplemente ir a Dialog incluido y subclase para mantener esta lógica.

Como beneficio adicional, las clases internas no anónimas hacen que la depuración sea un poco menos dolorosa porque tiene más identificadores de clase informativos disponibles para usted.


No creo que haya un problema con tu código. A veces tengo que recurrir a algo similar, pero utilizo una clase especial que envuelve el valor y llamo a un setter en la clase interna, pero el resultado final es el mismo.

private static class Result{ private Integer value; //getter and setters here } .... final Result result = new Result(); ... new InnerClass(){ void foo(){ result.setValue(42); } }

El problema es que las clases internas solo pueden hacer referencia a variables finales ya que su dirección de memoria no cambiará.

Mi único consejo para usted es no usar un int[] como valor sino un Integer[] para que pueda distinguir entre un valor de 0 y el valor que no se establece (que tendría el valor = nulo).


Si el código es legible, lo cual es, no diría que hacerlo de esa manera es terrible.

Una alternativa es hacer que JButton invoque una función en la clase que tiene showDialog (que está permitido). La función podría establecer una variable de instancia que se devolverá. Pero eso me parece menos legible, así que preferiría tu método.

A menos que esté haciendo un marco de IU profundamente jerárquico, a veces estos pequeños hacks son exactamente el tipo de cosas que debe hacer.

Si le preocupa, puede hacer básicamente lo mismo con una clase interna privada:

private class DialogReturnValue { public int value; } private int showDialog() { final DialogReturnValue myValue = new DialogReturnValue(); JPanel panel = new JPanel(); final JDialog dialog = new JDialog(mainWindow, "Hit the button", true); dialog.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE ); JButton button = new JButton("Hit me!"); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { myValue.value = 42; dialog.setVisible(false); } }); panel.add(button); dialog.add(panel); dialog.pack(); dialog.setVisible(true); return myValue.value; }

Y también hay ActionListeners para mirar (que bien puede ser el enfoque "correcto").


Usar AtomicInteger o AtomicReference puede hacer que sea un poco mejor. En realidad, es una práctica común, pero puede hacerlo más limpio al introducir la clase real que implementa ActionListener y proporciona el valor a través de un getter.