2
I took a look at that question You can pass methods as a parameter? and tried to invoke a method from one class, in another, passing as parameters the screen/class and the method name.
The purpose of doing this, is that in my application, I do several routines within a given method, which is triggered by an event (a ActionListener
, for example) and every time I need to do something "different", I have to overwrite the event that triggers this method, put the new routine and sometimes even repeat others.
I believe that by doing so, I could have a greater possibility in doing some routines. I could have several different screens with the component MyField
which does the same function, and on the screens I want a particular method to be executed together or after the methods of MyField
, I would do it quietly, passing it as parameter.
Apparently, it seemed to me a coherent idea, but I could be mistaken, and in this case, I’m open to more efficient and "correct suggestions".
To illustrate better what I intend, I made a simple example.
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class TesteReflection extends JFrame {
public static void main(String[] args) {
Runnable startApp = () -> {
TesteReflection tr = new TesteReflection();
};
SwingUtilities.invokeLater(startApp);
}
private MyField myField = new MyField();
private JButton button = new JButton("Click !");
public TesteReflection() {
add(button);
setSize(300, 200);
setVisible(true);
button();
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void button() {
button.addActionListener(e -> {
metodoA();
});
}
private void metodoA() {
MyField.actions(myField, TesteReflection.class, "metodoB");
}
private void metodoB() {
System.out.println("Método B");
//faz alguma coisa ..
}
}
import java.lang.reflect.Method;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class MyField extends JPanel {
private JTextField jTextField = new JTextField();
public MyField() {
actions();
}
private void actions() {
jTextField.addActionListener(e -> {
//faz alguma coisa ..
});
}
public static void actions(MyField component, Class tela, String methodName) {
component.getjTextField().addActionListener(e -> {
try {
//Method method = tela.getDeclaredMethod(methodName, new Class[]{});
Method method = tela.getClass().getDeclaredMethod(methodName, String.class);
method.setAccessible(true);
method.invoke(tela);
System.out.println("Chamei com sucesso o método " + methodName);
} catch (Exception ev) {
ev.printStackTrace();
}
});
}
public JTextField getjTextField() {
return jTextField;
}
}
What the :: does ? It’s some kind of "test" ?
– Gustavo Santos
@Gustavosantos Is the method Reference (reference to method). In this case the
this::metodoB
means "the methodmetodoB
of the objectthis
". The compiler strives to find out which functional interface (an interface that only has a single abstract method) is compatible with the reference and context in which it is used. In this case, it is compatible withRunnable
, for the return isvoid
, themetodoB
does not receive parameters and it is being used as a parameter to a call where the type isRunnable
. [continues...]– Victor Stafusa
[...continuation] With this, it’s more or less like the compiler replaces
this::metodoB
fornew Runnable() { public void run() { metodoB(); }}
.– Victor Stafusa
understood ! And not wanting to abuse your help, more, what happens when the method has parameters, or some kind of return ?
– Gustavo Santos
@Gustavosantos The compiler looks at which functional interfaces can be used in context and which are the possible methods the program refers to (as they can be overloaded, there may be more than one). Then it checks which of the possible methods is compatible with which possible functional interface and gives error if there is more than one possibility or if there is none. Remember that the functional interface method can have different returns, different types of parameters and different exceptions declared, all this is taken into account to check whether it is compatible or not.
– Victor Stafusa
when a method has parameters, I can’t use method Reference, or even Reflection. How would that be possible? Java has a method, implementation or something else, which allows me to invoke a method with parameters ?
– Gustavo Santos
@Gustavosantos Yes, you get it in both cases, both with method References and with Reflection. Let’s assume that
metodoB
had a type parameterJLabel
and return aString
. In that case, if the methodactions
receiveFunction<JLabel, String>
, compiler would see that this would be the compatible functional interface. In the case of Reflection, you would useclasse.getDeclaredMethod(methodName, JLabel.class);
andmethod.invoke(tela, algumaJLabel);
. The call toinvoke
returnsObject
, in the case of what is returned by the method invoked by Reflection.– Victor Stafusa
Function expects two values, correct ? However, if the method is void and passes only parameter, what is used ?
– Gustavo Santos
@Gustavosantos Não.
Function<A, B>
has a type parameterA
and a comeback of the kindB
. In the case ofvoid
with a parameterX
, useConsumer<X>
. Take a look at the package interfacesjava.util.function
that there is that most of them are defined (with the exception ofRunnable
). If you’re in a case where none of the existing functional interfaces serve, invent yours: just declare an interface with a single abstract method and if your method has a compatible format, the compiler accepts the method Reference.– Victor Stafusa
Very good, I’ll give a deal for sure. Thank you !
– Gustavo Santos