이것은 일반적이고 사소한 것일 수 있지만 구체적인 답변을 찾는 데 어려움을 겪고있는 것 같습니다. C #에는 델리게이트의 개념이 있는데, 이는 C ++의 함수 포인터 개념과 밀접한 관련이 있습니다. Java에도 비슷한 기능이 있습니까? 포인터가 다소 없다는 것을 감안할 때 가장 좋은 방법은 무엇입니까? 그리고 분명히, 우리는 여기서 일등석으로 이야기하고 있습니다.
이것은 일반적이고 사소한 것일 수 있지만 구체적인 답변을 찾는 데 어려움을 겪고있는 것 같습니다. C #에는 델리게이트의 개념이 있는데, 이는 C ++의 함수 포인터 개념과 밀접한 관련이 있습니다. Java에도 비슷한 기능이 있습니까? 포인터가 다소 없다는 것을 감안할 때 가장 좋은 방법은 무엇입니까? 그리고 분명히, 우리는 여기서 일등석으로 이야기하고 있습니다.
답변:
함수 포인터와 같은 기능에 대한 Java 관용구는 인터페이스를 구현하는 익명 클래스입니다.
Collections.sort(list, new Comparator<MyClass>(){
public int compare(MyClass a, MyClass b)
{
// compare objects
}
});
업데이트 : 위는 Java 8 이전의 Java 버전에서 필요합니다. 이제 우리는 훨씬 더 좋은 대안, 즉 람다를 가지고 있습니다.
list.sort((a, b) -> a.isGreaterThan(b));
방법 참조 :
list.sort(MyClass::isGreaterThan);
std::bind
매개 변수를 함수에 바인딩하고 호출 가능한 객체를 반환하는 조차 있습니다 . 이러한 이유로 C를 방어 할 수는 없지만 C ++ 은 Java보다 실제로 좋습니다.
인터페이스로 함수 포인터를 대체 할 수 있습니다. 컬렉션을 살펴보고 각 요소로 무언가를 수행한다고 가정 해 봅시다.
public interface IFunction {
public void execute(Object o);
}
이것은 우리가 CollectionUtils2.doFunc (Collection c, IFunction f)에 전달할 수있는 인터페이스입니다.
public static void doFunc(Collection c, IFunction f) {
for (Object o : c) {
f.execute(o);
}
}
예를 들어 숫자 모음이 있고 모든 요소에 1을 추가하고 싶다고 가정하십시오.
CollectionUtils2.doFunc(List numbers, new IFunction() {
public void execute(Object o) {
Integer anInt = (Integer) o;
anInt++;
}
});
반사를 사용하여 수행 할 수 있습니다.
객체와 메소드 이름을 문자열로 매개 변수로 전달한 다음 메소드를 호출하십시오. 예를 들면 다음과 같습니다.
Object methodCaller(Object theObject, String methodName) {
return theObject.getClass().getMethod(methodName).invoke(theObject);
// Catch the exceptions
}
그런 다음 다음과 같이 사용하십시오.
String theDescription = methodCaller(object1, "toString");
Class theClass = methodCaller(object2, "getClass");
물론 모든 예외를 확인하고 필요한 캐스트를 추가하십시오.
아니요, 함수는 Java의 첫 번째 클래스 객체가 아닙니다. 핸들러 클래스를 구현하여 동일한 작업을 수행 할 수 있습니다. 이것은 Swing 등에서 콜백이 구현되는 방식입니다.
그러나 자바의 차기 버전에서는 클로저 (당신이 말하는 것에 대한 공식 이름)에 대한 제안이 있습니다 -Javaworld 는 흥미로운 기사를 가지고 있습니다.
비슷한 기능을 달성하기 위해 익명의 내부 클래스를 사용할 수 있습니다.
인터페이스를 정의하려는 경우 Foo
:
interface Foo {
Object myFunc(Object arg);
}
bar
'함수 포인터'를 인수로받을 메소드 를 작성하십시오 .
public void bar(Foo foo) {
// .....
Object object = foo.myFunc(argValue);
// .....
}
마지막으로 다음과 같이 메소드를 호출하십시오.
bar(new Foo() {
public Object myFunc(Object arg) {
// Function code.
}
}
Java8은 람다 및 메소드 참조를 도입했습니다 . 따라서 함수가 기능 인터페이스 와 일치하면 (자신의 인터페이스 를 만들 수 있음)이 경우 메서드 참조를 사용할 수 있습니다.
Java는 공통 기능 인터페이스 세트를 제공합니다 . 반면 다음을 수행 할 수 있습니다.
public class Test {
public void test1(Integer i) {}
public void test2(Integer i) {}
public void consumer(Consumer<Integer> a) {
a.accept(10);
}
public void provideConsumer() {
consumer(this::test1); // method reference
consumer(x -> test2(x)); // lambda
}
}
alias
public List<T> collect(T t) = Collections::collect
Java에는 그런 것이 없습니다. 해당 객체의 메소드에 대한 참조를 전달하려면 함수를 일부 객체로 랩핑하고 해당 객체에 대한 참조를 전달해야합니다.
구문 상, 이것은 내부 클래스로 정의 된 익명 클래스 또는 클래스의 멤버 변수로 정의 된 익명 클래스를 사용하여 어느 정도 완화 될 수 있습니다.
예:
class MyComponent extends JPanel {
private JButton button;
public MyComponent() {
button = new JButton("click me");
button.addActionListener(buttonAction);
add(button);
}
private ActionListener buttonAction = new ActionListener() {
public void actionPerformed(ActionEvent e) {
// handle the event...
// note how the handler instance can access
// members of the surrounding class
button.setText("you clicked me");
}
}
}
리플렉션을 사용하여 Java에서 콜백 / 델리게이트 지원을 구현했습니다. 자세한 내용과 작업 소스는 내 웹 사이트에서 확인할 수 있습니다 .
작동 원리
WithParms라는 중첩 클래스가있는 Callback이라는 기본 클래스가 있습니다. 콜백이 필요한 API는 콜백 객체를 매개 변수로 사용하고 필요한 경우 메서드 변수로 Callback.WithParms를 만듭니다. 이 객체의 많은 응용 프로그램이 재귀 적이므로 매우 깨끗하게 작동합니다.
성능이 여전히 나에게 우선 순위가 높기 때문에 모든 호출에 대한 매개 변수를 보유하기위한 객관적인 객체 배열을 만들고 싶지 않았습니다. 결국 큰 데이터 구조에는 수천 개의 요소가 있으며 메시지 처리가 가능합니다. 시나리오 우리는 초당 수천 개의 데이터 구조를 처리 할 수 있습니다.
스레드 안전을 위해서는 매개 변수 배열이 API 메소드를 호출 할 때마다 고유하게 존재해야하며 효율성을 위해 콜백을 호출 할 때마다 동일한 배열을 사용해야합니다. 콜백을 호출하기 위해 매개 변수 배열로 바인딩하기 위해 만들 저렴한 두 번째 객체가 필요했습니다. 그러나 일부 시나리오에서는 호출자가 다른 이유로 이미 매개 변수 배열을 가지고있을 것입니다. 이 두 가지 이유로 인해 매개 변수 배열은 콜백 객체에 속하지 않았습니다. 또한 매개 변수를 배열 또는 개별 객체로 전달하는 호출 선택은 콜백을 사용하여 API의 손에 속하며 내부 작업에 가장 적합한 호출을 사용할 수 있습니다.
WithParms 중첩 클래스는 선택 사항이며 두 가지 용도로 사용되며 콜백 호출에 필요한 매개 변수 객체 배열을 포함하며 매개 변수 배열을로드 한 다음 10 개의 오버로드 된 invoke () 메서드 (1-10 개의 매개 변수 포함)를 제공합니다. 콜백 대상을 호출하십시오.
lambdaj 라이브러리에서 클로저가 어떻게 구현되었는지 확인하십시오. 실제로 C # 대리자와 매우 유사한 동작이 있습니다.
여기에있는 대부분의 사람들과 관련하여 Java를 처음 사용하지만 비슷한 제안을 보지 못했기 때문에 제안 할 다른 대안이 있습니다. 좋은 습관인지 아닌지 확실하지 않거나, 심지어 전에 제안했지만 나는 그것을 얻지 못했습니다. 나는 자기 묘사 적이라고 생각하기 때문에 그것을 좋아합니다.
/*Just to merge functions in a common name*/
public class CustomFunction{
public CustomFunction(){}
}
/*Actual functions*/
public class Function1 extends CustomFunction{
public Function1(){}
public void execute(){...something here...}
}
public class Function2 extends CustomFunction{
public Function2(){}
public void execute(){...something here...}
}
.....
/*in Main class*/
CustomFunction functionpointer = null;
그런 다음 응용 프로그램에 따라
functionpointer = new Function1();
functionpointer = new Function2();
기타
에 의해 전화
functionpointer.execute();