IT

자바 대표?

lottoking 2020. 5. 14. 08:19
반응형

자바 대표?


Java 언어에는 C #이 대리자를 지원하는 방식과 비슷한 대리자 기능이 있습니까?


아니, 아니

리플렉션을 사용하여 호출 할 수있는 Methods 객체를 가져와 동일한 효과를 얻을 수 있으며, 다른 방법은 단일 'invoke'또는 'execute'메소드로 인터페이스를 만든 다음 인스턴스화하여 메소드를 호출하는 것입니다. 익명의 내부 클래스 사용에 관심이 있습니다.

이 기사가 흥미롭고 유용하다는 것을 알 수있을 것이다 : 자바 프로그래머가 C # 대표단을 본다


정확히 무엇을 의미하는지에 따라 전략 패턴을 사용하여 유사한 효과를 얻을 수 있습니다.

다음과 같은 이름의 메소드 서명을 선언하는 대신

// C#
public delegate void SomeFunction();

인터페이스를 선언하십시오.

// Java
public interface ISomeBehaviour {
   void SomeFunction();
}

메소드를 구체적으로 구현하려면 동작을 구현하는 클래스를 정의하십시오.

// Java
public class TypeABehaviour implements ISomeBehaviour {
   public void SomeFunction() {
      // TypeA behaviour
   }
}

public class TypeBBehaviour implements ISomeBehaviour {
   public void SomeFunction() {
      // TypeB behaviour
   }
}

그런 다음 SomeFunctionC #에서 대리자 가 있었을 때마다 ISomeBehaviour참조를 대신 사용하십시오.

// C#
SomeFunction doSomething = SomeMethod;
doSomething();
doSomething = SomeOtherMethod;
doSomething();

// Java
ISomeBehaviour someBehaviour = new TypeABehaviour();
someBehaviour.SomeFunction();
someBehaviour = new TypeBBehaviour();
someBehaviour.SomeFunction();

익명의 내부 클래스를 사용하면 별도의 명명 된 클래스를 선언하지 않고 실제 대리자 함수처럼 취급 할 수 있습니다.

// Java
public void SomeMethod(ISomeBehaviour pSomeBehaviour) {
   ...
}

...

SomeMethod(new ISomeBehaviour() { 
   @Override
   public void SomeFunction() {
      // your implementation
   }
});

이것은 아마도 구현이 현재 상황에 매우 구체적이고 재사용으로 이익을 얻지 못할 때에 만 사용해야합니다.

그리고 물론 Java 8에서는 기본적으로 람다식이됩니다.

// Java 8
SomeMethod(() -> { /* your implementation */ });

짧은 이야기 : 아니다 .

소개

Microsoft Visual J ++ 개발 환경의 최신 버전은 델리게이트 또는 바인딩 된 메서드 참조 라는 언어 구성을 지원합니다 . 이 구조, 그리고 새로운 키워드 delegatemulticast이를 지원하기 위해 도입은 자바의 일부가 아닌 TM에 의해 지정되는 프로그래밍 언어, Java 언어 사양 에 의해 및 개정 사양 내부 클래스 에 포함 JDKTM 1.1 소프트웨어에 대한 문서 .

Java 프로그래밍 언어에이 구성이 포함될 가능성은 거의 없습니다. Sun은 이미 프로토 타입 제작 및 폐기에 이르기까지 1996 년에 채택을 신중하게 고려했습니다. 우리의 결론은 바인딩 된 메소드 참조가 불필요하고 언어에 해롭다는 것이 었습니다. 이 결정은 Delphi Object Pascal에서 바인딩 된 메소드 참조에 대한 경험이있는 Borland International과상의하여 이루어졌습니다.

우리는 바인딩 된 메소드 참조가 불필요하다고 생각합니다. 다른 디자인 대안 인 inner class 는 동일하거나 우수한 기능을 제공 하기 때문 입니다. 특히 내부 클래스는 사용자 인터페이스 이벤트 처리 요구 사항을 완벽하게 지원하며 최소한 Windows Foundation 클래스만큼 포괄적 인 사용자 인터페이스 API를 구현하는 데 사용되었습니다.

우리는 바인딩 된 메소드 참조가 Java 프로그래밍 언어의 단순성과 API의 객체 지향적 특성을 떨어 뜨리기 때문에 유해 하다고 생각 합니다. 바운드 메소드 참조는 언어 구문 및 범위 지정 규칙에 불규칙성을 유발합니다. 마지막으로 VM은 별도의 다른 유형의 참조 및 메서드 연결을 효율적으로 처리해야하므로 VM 기술에 대한 투자를 줄입니다.


읽은 :

대리인은 이벤트 기반 시스템에서 유용한 구성입니다. 본질적으로 위임은 지정된 객체에서 메소드 디스패치를 ​​인코딩하는 객체입니다. 이 문서는 Java 내부 클래스가 어떻게 이러한 문제에 대한보다 일반적인 솔루션을 제공하는지 보여줍니다.

대리인이란 무엇입니까? 실제로 C ++에서 사용되는 멤버 함수에 대한 포인터와 매우 유사합니다. 그러나 델리게이트에는 호출 할 메소드와 함께 대상 오브젝트가 포함됩니다. 이상적으로 말할 수 있으면 좋을 것입니다.

obj.registerHandler (ano.methodOne);

.. 그리고 특정 이벤트가 수신되면 메소드 methodOne이 ano에서 호출됩니다.

이것이 델리게이트 구조가 달성하는 것입니다.

자바 내부 클래스

Java는 익명의 내부 클래스를 통해이 기능을 제공하므로 추가 Delegate 구문이 필요하지 않다고 주장했습니다.

obj.registerHandler(new Handler() {
        public void handleIt(Event ev) {
            methodOne(ev);
        }
      } );

언뜻보기에 이것은 정확하지만 동시에 귀찮은 것 같습니다. 많은 이벤트 처리 예제의 경우 Delegates 구문의 단순성이 매우 매력적입니다.

일반 처리기

그러나, 예를 들어, 일반적인 비동기식 프로그래밍 환경의 일부로서, 이벤트 기반 프로그래밍이보다 널리 사용되는 방식으로 사용된다면 더 많은 위험이 따릅니다.

이러한 일반적인 상황에서는 대상 메소드와 대상 오브젝트 인스턴스 만 포함하는 것만으로는 충분하지 않습니다. 일반적으로 이벤트 핸들러가 등록 될 때 컨텍스트 내에서 결정되는 다른 매개 변수가 필요할 수 있습니다.

이보다 일반적인 상황에서 java 접근 방식은 특히 최종 변수 사용과 결합 할 때 매우 우아한 솔루션을 제공 할 수 있습니다.

void processState(final T1 p1, final T2 dispatch) { 
  final int a1 = someCalculation();

  m_obj.registerHandler(new Handler() {
    public void handleIt(Event ev) {
     dispatch.methodOne(a1, ev, p1);
    }
  } );
}

최종 * 최종 * 최종

관심있어?

최종 변수는 익명 클래스 메소드 정의 내에서 액세스 할 수 있습니다. 파급 효과를 이해하려면이 코드를주의해서 연구하십시오. 이것은 잠재적으로 매우 강력한 기술입니다. 예를 들어, MiniDOM 및보다 일반적인 상황에서 처리기를 등록 할 때 효과적 일 수 있습니다.

대조적으로 Delegate 구문은 이러한 일반적인 요구 사항에 대한 솔루션을 제공하지 않으므로 디자인을 기반으로 할 수있는 관용구로 거부해야합니다.


나는이 게시물이 오래되었다는 것을 알고 있지만 Java 8은 람다와 기능 인터페이스의 개념을 추가했습니다. 기능 인터페이스는 하나의 메소드 만있는 인터페이스입니다. 이 둘은 C # 대리자와 비슷한 기능을 제공합니다. 자세한 내용을 보려면 여기를 참조하거나 Google Java Lambdas를 참조하십시오. http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html


아니요, 그러나 프록시와 리플렉션을 사용하여 위조 가능합니다.

  public static class TestClass {
      public String knockKnock() {
          return "who's there?";
      }
  }

  private final TestClass testInstance = new TestClass();

  @Test public void
  can_delegate_a_single_method_interface_to_an_instance() throws Exception {
      Delegator<TestClass, Callable<String>> knockKnockDelegator = Delegator.ofMethod("knockKnock")
                                                                   .of(TestClass.class)
                                                                   .to(Callable.class);
      Callable<String> callable = knockKnockDelegator.delegateTo(testInstance);
      assertThat(callable.call(), is("who's there?"));
  }

이 관용구의 좋은 점은 위임자가 작성되는 시점에서 위임 된 메소드가 존재하고 필요한 서명이 있는지 확인할 수 있다는 것입니다 (불행히도 FindBugs 플러그인은 컴파일 타임에는 아니지만) 여기에서 도움을 받으십시오) 그런 다음 안전하게 사용하여 다양한 인스턴스에 위임하십시오.

더 많은 테스트구현 에 대해서는 githubkarg 코드를 참조하십시오 .


리플렉션을 사용하여 Java에서 콜백 / 델리게이트 지원을 구현했습니다. 자세한 내용과 작업 소스는 내 웹 사이트에서 확인할 수 있습니다 .

작동 원리

WithParms라는 중첩 클래스가있는 Callback이라는 기본 클래스가 있습니다. 콜백이 필요한 API는 콜백 객체를 매개 변수로 사용하고 필요한 경우 메서드 변수로 Callback.WithParms를 만듭니다. 이 객체의 많은 응용 프로그램이 재귀 적이므로 매우 깨끗하게 작동합니다.

성능이 여전히 나에게 우선 순위가 높기 때문에 모든 호출에 대한 매개 변수를 보유하기위한 객관적인 객체 배열을 만들고 싶지 않았습니다. 결국 큰 데이터 구조에는 수천 개의 요소가 있으며 메시지 처리가 가능합니다. 시나리오 우리는 초당 수천 개의 데이터 구조를 처리 할 수 ​​있습니다.

스레드 안전을 위해서는 매개 변수 배열이 API 메소드를 호출 할 때마다 고유하게 존재해야하며 효율성을 위해 콜백을 호출 할 때마다 동일한 배열을 사용해야합니다. 콜백을 호출하기 위해 매개 변수 배열로 바인딩하기 위해 만들 저렴한 두 번째 객체가 필요했습니다. 그러나 일부 시나리오에서는 호출자가 다른 이유로 이미 매개 변수 배열을 가지고있을 것입니다. 이 두 가지 이유로 인해 매개 변수 배열은 콜백 객체에 속하지 않습니다. 또한 매개 변수를 배열 또는 개별 객체로 전달하는 호출 선택은 콜백을 사용하여 API의 손에 속하며 내부 작업에 가장 적합한 호출을 사용할 수 있습니다.

The WithParms nested class, then, is optional and serves two purposes, it contains the parameter object array needed for the callback invocations, and it provides 10 overloaded invoke() methods (with from 1 to 10 parameters) which load the parameter array and then invoke the callback target.

What follows is an example using a callback to process the files in a directory tree. This is an initial validation pass which just counts the files to process and ensure none exceed a predetermined maximum size. In this case we just create the callback inline with the API invocation. However, we reflect the target method out as a static value so that the reflection is not done every time.

static private final Method             COUNT =Callback.getMethod(Xxx.class,"callback_count",true,File.class,File.class);

...

IoUtil.processDirectory(root,new Callback(this,COUNT),selector);

...

private void callback_count(File dir, File fil) {
    if(fil!=null) {                                                                             // file is null for processing a directory
        fileTotal++;
        if(fil.length()>fileSizeLimit) {
            throw new Abort("Failed","File size exceeds maximum of "+TextUtil.formatNumber(fileSizeLimit)+" bytes: "+fil);
            }
        }
    progress("Counting",dir,fileTotal);
    }

IoUtil.processDirectory():

/**
 * Process a directory using callbacks.  To interrupt, the callback must throw an (unchecked) exception.
 * Subdirectories are processed only if the selector is null or selects the directories, and are done
 * after the files in any given directory.  When the callback is invoked for a directory, the file
 * argument is null;
 * <p>
 * The callback signature is:
 * <pre>    void callback(File dir, File ent);</pre>
 * <p>
 * @return          The number of files processed.
 */
static public int processDirectory(File dir, Callback cbk, FileSelector sel) {
    return _processDirectory(dir,new Callback.WithParms(cbk,2),sel);
    }

static private int _processDirectory(File dir, Callback.WithParms cbk, FileSelector sel) {
    int                                 cnt=0;

    if(!dir.isDirectory()) {
        if(sel==null || sel.accept(dir)) { cbk.invoke(dir.getParent(),dir); cnt++; }
        }
    else {
        cbk.invoke(dir,(Object[])null);

        File[] lst=(sel==null ? dir.listFiles() : dir.listFiles(sel));
        if(lst!=null) {
            for(int xa=0; xa<lst.length; xa++) {
                File ent=lst[xa];
                if(!ent.isDirectory()) {
                    cbk.invoke(dir,ent);
                    lst[xa]=null;
                    cnt++;
                    }
                }
            for(int xa=0; xa<lst.length; xa++) {
                File ent=lst[xa];
                if(ent!=null) { cnt+=_processDirectory(ent,cbk,sel); }
                }
            }
        }
    return cnt;
    }

This example illustrates the beauty of this approach - the application specific logic is abstracted into the callback, and the drudgery of recursively walking a directory tree is tucked nicely away in a completely reusable static utility method. And we don't have to repeatedly pay the price of defining and implementing an interface for every new use. Of course, the argument for an interface is that it is far more explicit about what to implement (it's enforced, not simply documented) - but in practice I have not found it to be a problem to get the callback definition right.

Defining and implementing an interface is not really so bad (unless you're distributing applets, as I am, where avoiding creating extra classes actually matters), but where this really shines is when you have multiple callbacks in a single class. Not only is being forced to push them each into a separate inner class added overhead in the deployed application, but it's downright tedious to program and all that boiler-plate code is really just "noise".


While it is nowhere nearly as clean, but you could implement something like C# delegates using a Java Proxy.


No, but it has similar behavior, internally.

In C# delegates are used to creates a separate entry point and they work much like a function pointer.

In java there is no thing as function pointer (on a upper look) but internally Java needs to do the same thing in order to achieve these objectives.

For example, creating threads in Java requires a class extending Thread or implementing Runnable, because a class object variable can be used a memory location pointer.


Yes & No, but delegate pattern in Java could be thought of this way. This video tutorial is about data exchange between activity - fragments, and it has great essence of delegate sorta pattern using interfaces.

Java Interface


It doesn't have an explicit delegate keyword as C#, but you can achieve similar in Java 8 by using a functional interface (i.e. any interface with exactly one method) and lambda:

private interface SingleFunc {
    void printMe();
}

public static void main(String[] args) {
    SingleFunc sf = () -> {
        System.out.println("Hello, I am a simple single func.");
    };
    SingleFunc sfComplex = () -> {
        System.out.println("Hello, I am a COMPLEX single func.");
    };
    delegate(sf);
    delegate(sfComplex);
}

private static void delegate(SingleFunc f) {
    f.printMe();
}

Every new object of type SingleFunc must implement printMe(), so it is safe to pass it to another method (e.g. delegate(SingleFunc)) to call the printMe() method.


Java doesn't have delegates and is proud of it :). From what I read here I found in essence 2 ways to fake delegates: 1. reflection; 2. inner class

Reflections are slooooow! Inner class does not cover the simplest use-case: sort function. Do not want to go into details, but the solution with inner class basically is to create a wrapper class for an array of integers to be sorted in ascending order and an class for an array of integers to be sorted in descending order.

참고URL : https://stackoverflow.com/questions/44912/java-delegates

반응형