【问题标题】:Anonymous inner class example validity concern匿名内部类示例有效性问题
【发布时间】:2017-11-28 23:01:59
【问题描述】:

我试图使用我曾经购买的火花图表来复习一些 Java 语言。关于匿名内部类的使用,他们给出了这个例子:

Dice rollDice() {
    return new Dice() {
        int number = (int)( Math.random() * 6 ) + 1;
    };
}

问题是,我看不出这是如何工作的,也无法让编译器接受它作为另一个类中的方法。编译器抱怨每次对 Dice 的引用“找不到符号”。

我是否没有正确理解他们的示例,或者这是完全无效的代码?提前致谢!

附言如果这是工作代码,有人可以提供一个如何使用它的示例吗?

编辑:我终于找到了一些有意义的东西 匿名内部类的语法如下所示

new SuperClassName/InterfaceName() {
// Implement or override methods in superclass or interface
// Other methods if necessary
}

上面的代码被传递给一个方法,该方法接受一个超类的实例或完全实现接口。例如,一个具有EventHandler参数的方法,我们还没有定义一个实现handle(ActionEvent e)方法的类。

enlargeButton.setOnAction(
    new EventHandler<ActionEvent>() {
        public void handle(ActionEvent e) {
            circlePane.enlarge();
        }
    });

这样,它将真正匿名。我认为Java自己的教程中给出的示例非常糟糕。

【问题讨论】:

  • Java 没有标准的Dice 类,因此“找不到符号”。该示例可能包含您未向我们展示的其他部分。无论如何,这看起来不像是使用匿名内部类的首选方式,这使得这个示例更加不清楚。
  • 不,该示例不包含我没有向您展示的其他部分。这就是我问这个问题的原因,我很不清楚,我想知道我是没有正确阅读它还是真的不理解这个例子的使用。我现在假设他们的例子只是垃圾。
  • 如果您将它放在class Dice{...} 中,该代码将会编译。但是这个例子仍然不是很有用,因为我们只是将随机数包装在 Dice 对象中。这样的骰子不会让我们返回所有 1-6 个数字,它只能返回一个数字,这使得这个例子至少不清楚。如果您想了解匿名课程,请考虑使用官方教程,例如 docs.oracle.com/javase/tutorial/java/javaOO/…
  • 他们在java教程中的例子似乎完全无视“匿名”的想法。正如我所学的,之前在他们自己的教程中定义的“匿名”意味着它没有分配给变量而只是使用。然而,他们将这些对象分配给变量frenchGreetingenglishGreeting。它有一个声明的名称,因此不是匿名的。
  • 我想知道是什么让您认为““匿名”意味着它没有分配给变量”,因为这不是真的。匿名类是没有任何 特定 名称的类,因此您不能在其他地方重用它来重新实例化它(至少不是通常情况下,您可以通过反射来实现,但事实并非如此)。但我们并不真正关心该类的名称是什么,我们只关心该类的实例如何表现。例如,我们可以创建一个像 ActionListener al = new ActionListener(){ ... } 这样的 ActionListener 并将其传递给许多按钮。

标签: java class inner-classes


【解决方案1】:

您似乎已经回答了大部分自己的问题,并且您可能希望通过一些完整的教程或文档来完全理解事情,但这里有一些您直接问题的答案。

在您拥有可以扩展的 Dice 类或接口之前,您的第一个示例代码不会编译。因此,作为示例,您可以编译此代码:

class Dicey {
    interface Dice {
    }
    Dice rollDice() {
        return new Dice() {
            int number = (int) (Math.random() * 6) + 1;
        };
    }
    public static void main(String... none) {
        Dice dice = new Dicey().rollDice();
        // dice.number; <-- not available
    }
}

现在您可以执行此操作,但是您怀疑这不是一件非常有用的事情(出于几个原因),但最大的问题是,在您创建了这个匿名实例之后,并没有真正的方法可以访问.nu​​mber 成员。

通常你会让一个匿名子类在接口上实现一些方法,这样你就可以用它做一些事情。比如

class HelloAnonymous {
    interface Hello {
        String say();
    }

    Hello hello(String world) {
        return new Hello() {
            public String say() {
                return world;
            }
        };
    }

    public static void main(String... none) {
        System.out.println(new HelloAnonymous().hello("world").say());
        // prints 'world'
    }
}

为您提供了一种制作非常有用的 Hello 对象的方法,这些对象可以说些什么。说了这么多,编写匿名内部类是相当老派的,因为现在函数式接口在很大程度上取代了对它们的需求。所以在这个例子中你可以:

class HelloAnonymous {
    @FunctionalInterface
    interface Hello {
        String say();
    }

    // old school
    Hello hello(String world) {
        return new Hello() {
            public String say() {
                return world;
            }
        };
    }

    // with lambda notation
    Hello alsoHello(String world) {
        return () -> {
            return world;
        };
    }

    public static void main(String... none) {
        System.out.println(new HelloAnonymous().hello("world").say());
        System.out.println(new HelloAnonymous().alsoHello("world").say());
    }
}

【讨论】:

    【解决方案2】:

    由于我不了解“骰子”类,我无法编写相同的方法,但我尝试了一些类似的方法。它编译和工作可以通过使用反射访问“数字”变量。我的意见是它不是很有用。以下是我的代码:

      public class TestClass {
    
        public static void main(String a[]){
          TestClass aClass = rollDice();
          try {
            System.out.println("value of number : " + aClass.getClass().getDeclaredField("number").getInt(aClass));
          }
          catch (NoSuchFieldException e) {
            e.printStackTrace();
          }
          catch (IllegalAccessException e) {
            e.printStackTrace();
          }
        }
    
         static TestClass rollDice() {
          return new TestClass() {
            int number = (int) (Math.random() * 6) + 1;
          };
        }
      }
    

    【讨论】:

      【解决方案3】:

      那个例子非常糟糕。把那个来源扔掉。试试这个:

      import java.util.Random;
      
      public class DieFactory {
        interface Die { int roll(); }
      
        static Die create(long seed) {
          Random random = new Random(seed);
          return new Die() {
            @Override
            public int roll() {
              return random.nextInt(6) + 1;
            }    
          };
        }
      
        // Now you can roll 2 dice pretty easily.
        public static void main(String [] args) {
          DieFactory.Die die1 = DieFactory.create(42);    
          DieFactory.Die die2 = DieFactory.create(24);    
          for (int i = 0; i < 40; i++) {
            System.out.println(die1.roll() + die2.roll());
          }
        }
      }
      

      顺便说一下,“骰子”这个词是单数“骰子”的复数形式。

      【讨论】:

        猜你喜欢
        • 2014-03-06
        • 1970-01-01
        • 2014-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-25
        • 1970-01-01
        相关资源
        最近更新 更多