【问题标题】:Equivalent of C++'s std::bind in Java?相当于Java中C++的std::bind?
【发布时间】:2013-02-24 15:13:21
【问题描述】:

有没有办法像在 C++ 中使用 std::bind 一样将参数参数绑定到 Java 中的函数指针?与这种类似的 Java 等价物是什么?

void PrintStringInt(const char * s, int n)
{
    std::cout << s << ", " << n << std::endl;
}

void PrintStringString(const char * s, const char * s2)
{
    std::cout << s << ", " << s2 << std::endl;
}

int main()
{
    std::vector<std::function<void(const char *)>> funcs;
    funcs.push_back(std::bind(&PrintStringInt, std::placeholders::_1, 4));
    funcs.push_back(std::bind(&PrintStringString, std::placeholders::_1, "bar"));
    for(auto i = funcs.begin(); i != funcs.end(); ++i){
        (*i)("foo");
    }
    return 0;
}

【问题讨论】:

    标签: java c++ functional-programming bind


    【解决方案1】:

    这与我认为您可以逐行翻译一样接近,bind 不会 1:1 映射到任何 Java 构造;

    static void PrintStringInt(String s, int n)
    {
        System.out.println(s + ", " + n);
    }
    
    static void PrintStringString(String s, String s2)
    {
        System.out.println(s + ", " + s2);
    }
    
    interface MyCall {
        void fn(String value);
    }
    
    public static void main(String[] argv)
    {
        Vector<MyCall> funcs = new Vector<MyCall>();
        funcs.add(new MyCall() { 
          @Override public void fn(String value) {PrintStringInt(value, 4); }});
        funcs.add(new MyCall() { 
          @Override public void fn(String value) {PrintStringString(value, "bar"); }});
        for(MyCall i : funcs){
            i.fn("foo");
        }
    }
    

    【讨论】:

      【解决方案2】:

      恐怕不是,但这段代码是一种模仿 C++ 模板的方法(很糟糕):

      abstract class Printer<T> {
         final T value;
         Printer( T v ) {
            value = v;
         }
         public abstract void print( String s );
      }
      
      class PrintStringInt extends Printer< Integer> {
         PrintStringInt( int v ) {
            super( v );
         }
         @Override public void print( String s ) {
            System.out.printf( "%s, %d\n", s, value );
         }
      }
      
      class PrintStringString extends Printer< String > {
         PrintStringString( String v ) {
            super( v );
         }
         @Override public void print( String s ) {
            System.out.printf( "%s, %s\n", s, value );
         }
      }
      
      public class BindTest {
         public static void main( String[] args ) {
            Printer<?>[] funcs = {
               new PrintStringInt( 4 ),
               new PrintStringString( "bar")
            };
            for( Printer<?> p : funcs ) {
                p.print( "foo" );
            }
         }
      }
      

      输出:

      foo, 4
      foo, bar
      

      【讨论】:

        【解决方案3】:

        从 Java7 开始,我们也可以对方法句柄做同样的事情,详见 java.lang.invoke.MethodHandle 类的 API 文档。

        【讨论】:

          【解决方案4】:

          使用 MethodHandle,这里是一个例子

          public class HW
          {
              int sum;
          
            public HW(int a, int b)
            {
              super();
              this.sum = a+b;
            }
          
          
            public void hello1(double c)
            {
              double newnumber = sum+c;
             System.out.println("hello from hello1, new number= " + newnumber);
            }
          
            public void hello2()
            {        
             System.out.println("hello from hello2, sum=" + sum);
            }
          }
          
          import java.lang.invoke.MethodHandle;
          import java.lang.invoke.MethodHandles;
          import java.lang.invoke.MethodType;
          
          
          public class TestMethodHandle
          {
          
          /**
           * @param args
           */
            public static void main(String[] args)
            {
          
              HW hw = new HW(10, 15);
              MethodHandles.Lookup lookup = MethodHandles.lookup();
              MethodHandle mh;
              try
              {
                  mh = lookup.findVirtual(HW.class, "hello2",
                                                       MethodType.methodType(void.class));
                  mh.invoke(hw);
          
                  mh = lookup.findVirtual(HW.class, "hello1",
                          MethodType.methodType(void.class, double.class));
                  mh.invoke(hw, 20);
          
              } catch (NoSuchMethodException e)
              {
                  e.printStackTrace();
              } catch (IllegalAccessException e)
              {
                  e.printStackTrace();
              } catch (Throwable e)
              {
                  e.printStackTrace();
              }
          
          }
          

          【讨论】:

            【解决方案5】:

            您可以使用所需签名的函数创建一个匿名类,将调用转发到原始函数。

            假设你有这些功能:

            public class StringPrinter {
                public void printStringInt( String s, int n ) {
                   System.out.println( s + ", " + n );
                }
            
                public void printStringString( String s, String s2 ) {
                   System.out.println( s + ", " + s2 );
                }
            }
            

            然后您可以创建匿名类,将参数有效地绑定到这些函数。

            public static void main( String[] args ) {
                 public interface Print1String {
                     public void printString( String s );
                 }
            
                 List<Print1String> funcs = new ArrayList<Print1String);
                 funcs.add( new Print1String() {
                    public void printString( String s ) {
                        new StringPrinter( ).printStringInt( s, 42 ); 
                    }});
                 funcs.add( new Print1String() {
                    public void printString( String s ) {
                        new StringPrinter( ).printStringString( s, "bar" ); 
                    }});
            
                 for ( Print1String func : funcs ) {
                     func.print1String("foo");
                 }
            }
            

            【讨论】:

            • 对我来说'new'太多了,StringPrinter的两个方法可能是静态的
            • 在这种情况下,这些只是您可能希望将 绑定到 的示例。一般来说,优先使用实例方法而不是静态方法可以更好地支持以后继承和注入的可能性。
            • 这和std::bind不一样,std::bind在运行时是动态的,这个在编译时是静态的
            猜你喜欢
            • 2017-07-18
            • 2014-09-29
            • 2011-01-21
            • 1970-01-01
            • 1970-01-01
            • 2022-07-09
            • 2011-06-29
            • 2010-09-24
            • 2023-04-06
            相关资源
            最近更新 更多