【问题标题】:Is there an equivalent to C++ member function pointers in Java? [duplicate]Java中是否有与C++成员函数指针等价的东西? [复制]
【发布时间】:2011-05-15 20:48:15
【问题描述】:

在标记为 dup 之前,是的,我见过 Function Pointers in Java,不,它并没有真正回答我的问题,主要是因为我对 Java 还很陌生,所以我不太了解分配答案。

这是一种混合了 Java / C++ 的东西,在 Java 中有什么合理的方法可以做到这一点吗?

public class Foo {
    private int _data;

    /* various other functions */    

    public boolean test1( Foo other ) {  /* do test */ }
    public boolean test2( Foo other ) {  /* do test */ }
    public boolean test3( Foo other ) {  /* do test */ }
    public boolean test4( Foo other ) {  /* do test */ }
}

public class Bar {
    private Foo[] _foos = { /* Init an array of Foos */ };

    public Bar doSomething() {
        _foos = new Foo[4];

        _foos[0] = getTest(Foo::test1);
        _foos[1] = getTest(Foo::test2);
        _foos[2] = getTest(Foo::test3);
        _foos[3] = getTest(Foo::test4);
    }

    /* 
     * Now we only have a single function which takes function pointer.
     */
    private Foo _getTest(boolean Foo::*func()) {
        Foo current = _foos[ 0 ];

        for ( int i = 1; i != _foos.length; i++ )
            current = current.*func( _foos[ i ] ) ? _foos[ i ] : current;

        return current;
    }
}

【问题讨论】:

  • @ybungalobill:当您对一门语言足够陌生时,您可能没有足够的知识来提出特定问题。

标签: java c++


【解决方案1】:

您不能指向 Java 中的函数,并且没有直接的等价物。

我唯一能想到的就是 Function 对象。你知道,在 C++ 中你会重载函数调用运算符,

operator()

在 Java 中,您使用虚拟方法 doSomething 创建一个名为 Function 的接口,然后不像在 C 中那样使用函数指针数组,而是使用 Function 对象数组,其 doSomething然后调用方法。

【讨论】:

    【解决方案2】:

    Java 中的函数不是一流的对象。这意味着您可以做到这一点的最佳方法是通过子类化或实现接口。该接口将包含方法定义。然后,您实际上将使用所需的方法传递一个对象。例如查看 Collection.sort 的工作原理。

    【讨论】:

      【解决方案3】:

      不,Java 中根本没有函数这样的东西。只有对象和方法完全由对象拥有并从属于它们。对象是你的 java 中的主人和主人,除了他的意志之外什么都不会发生。

      您可以通过让您的对象实现委托接口来实现一种 java-delegation,这是尽可能接近的。

      public interface Func {
      
      boolean func(Foo foo);
      
      }
      
      public class Test1 implements Func {
      
      @Override
      public boolean func(Foo foo) {
        return doSomeStuff();
      }
      
      ...
      
      _foos[0] = getTest(new Test1());
      

      希望这足以让您了解这个想法。一般来说,您在应用程序代码中实际上并没有看到太多。

      编辑:

      由于您是 Java 新手,因此您可以通过语法来实际执行您想要执行的操作。这也可能说明它是什么皮塔饼以及为什么人们不喜欢它:)

      public class Bar {
      
        public static interface Func {
          boolean func(Foo current, Foo other);
        }
      
        public static Func test1 = new Func() {
          @Override
          public boolean func(Foo current, Foo other) {
            return current.test1(other);
          }
        };
      
        public Bar doSomething() {
          _foos = new Foo[4];
          _foos[0] = getTest(test1);
          //...
        }
      
        private Foo _getTest(Func func) {
          Foo current = _foos[ 0 ];
      
            for ( int i = 1; i != _foos.length; i++ ) {
              current = func(current, _foos[ i ] ) ? _foos[ i ] : current;
            }
          return current;
        }
      
      }
      

      【讨论】:

      • 呃,那个说“提交新答案”的橙色大坝太烦人了。您输入的内容与我完全相同,但速度更快:P
      • @Affe:你怎么没看到很多?看起来像是被广泛使用的 C++ 仿函数。
      • 深入研究我个人的观点,我认为很多教科书和早期的 Java 文献都包含了对倾向于与之配套的构造(例如,匿名实现)的普遍蔑视,并告诉我们如果你发现自己做了很多,你有一个“糟糕的 OO”或“一开始就不是 OO”的设计。那个“好”的面向对象代码不需要太多这种东西。 “如果你发现自己需要函数,那你就错过了 java 的意义。”等等等等等等。当然,我们确实使用了很多明显的例外,比如 Runnable 接口和 Comparator 接口。
      • @Affe:我可以把这个嵌套在 Bar 里面吗?
      • 是的,您可以在 Java 中嵌套接口。 'public static interface Func {...}' 等
      【解决方案4】:

      JDK8 可能会引入 lambda 和方法引用。

      与此同时,匿名内部类提供了一种稍微冗长的创建仿函数对象的方法。

      public interface FooTest {
          boolean test(Foo foo);
      }
      [...]
          FooTest[] tests = {
               new FooTest() { public void boolean test(Foo foo) {
                   return foo.test1();
               }},
               [...]
          };
      

      对于构建类似的测试框架,反射或使用注释处理器生成静态代码是可行的方法。 (请注意,通常反射是邪恶的,但在测试框架等情况下还可以。)

      【讨论】:

        【解决方案5】:

        考虑到语言的差异,将您的示例或多或少直接翻译成 Java。

        public abstract class PTMF { // Pointer To Member Function         
            // The object on which we are going to call the method
            public Foo self;
            // Common interface of the member functions we are going to call
            public abstract boolean test(Foo other);
        }
        
        public class Foo {
            private int _data;
        
            /* various other methods */
            public boolean test1(Foo other) { /* do test */ }
            public boolean test2(Foo other) { /* do test */ }
            public boolean test3(Foo other) { /* do test */ }
            public boolean test4(Foo other) { /* do test */ }
        }
        
        public class Bar {
            private Foo[] _foos = { /* Init an array of Foos */ };
        
            public Bar doSomething() {
                _foos = new Foo[4];
        
                // Here we are going to define inline some PTMFs
                // providing adapter implementations for our interface call.
        
                _foos[0] = getTest(
                    new PTMF() {                    
                        @Override public void test(Foo other) { 
                            return self.test1(other);
                        }
                    }
                );
                _foos[1] = getTest(
                    new PTMF() {
                        @Override public void test(Foo other) { 
                            return self.test2(other);
                        }
                    }
                );
                _foos[2] = getTest(
                    new PTMF() {
                        @Override public void test(Foo other) { 
                            return self.test3(other);
                        }
                    }
                );
                _foos[3] = getTest(
                    new PTMF() {
                        @Override public void test(Foo other) { 
                            return self.test4(other);
                        }
                    }
                );
            }
        
            /* 
             * Now we only have a single function which takes function pointer.
             */
            private Foo getTest(PTMF ptmf) {
                Foo current = _fos[0];
        
                for ( int i = 1; i != _foos.length; i++) {
                    // Set reference to called object
                    ptmf.self = current;
                    // Call PTMF
                    current = ptmf.test( _foos[ i ] ) ? _foos[ i ] : current;
                }    
                return current;
            }
        }
        

        请注意,在上面的示例中,PTMF 不是线程安全的。对于线程安全的实现,将 PTMF 更改为

        public class PTMF {
            public abstract boolean test(Foo self, Foo other);
        };
        

        或者,在这种情况下更好:

        public interface PTMF {
            boolean test(Foo self, Foo other);
        };
        

        getTest() 中的循环体将是:

        current = ptmf.test(current, _foos[ i ] ) ? _foos[ i ] : current;   
        

        【讨论】:

          猜你喜欢
          • 2015-08-04
          • 1970-01-01
          • 2022-01-10
          • 1970-01-01
          • 2011-04-07
          • 1970-01-01
          • 2017-07-27
          • 1970-01-01
          • 2018-05-26
          相关资源
          最近更新 更多