47

我有一个类,我们称之为 LineGraph,它呈现一个折线图。我需要对它进行子类化,但派生类只在一个地方使用,并且与使用它的类耦合。所以我正在使用一个内部类。

我看到两种方法可以做到这一点:

匿名内部类

public class Gui {
    LineGraph graph = new LineGraph() {
        // extra functionality here.
    };
}

命名内部类

public class Gui {
    MyLineGraph graph = new MyLineGraph();

    private class MyLineGraph extends LineGraph {
        // extra functionality here.
    }
}

我不是匿名内部类的粉丝,因为坦率地说,我只是觉得它看起来很丑。但是对于只在一个地方使用的子类,命名内部类是否过大?公认的做法是什么?

4

15 回答 15

53

匿名内部类的一个优点是没有人可以在其他任何地方使用它,而可以使用命名的内部类(如果只有创建它的类如果设为私有)。这是一个很小的区别,但这确实意味着您可以保护内部类不被意外使用到其他地方。

此外,使用匿名内部类可以让任何阅读您的代码的人都振作起来——“这个类只在这里使用,其他任何地方都没有。” 如果你看到一个命名的内部类,有人可能会认为它会在类中的多个地方使用。

它们非常相似,所以这两点都不会改变游戏规则。我只是认为,如果您一次性使用匿名内部类,并在类中多次使用它时命名内部类,这有助于清晰。

于 2009-04-03T16:12:17.837 回答
38

(反驳丹尼尔·卢)

匿名内部类的一个缺点是没有人可以在其他任何地方使用它,而可以使用命名的内部类(如果只有创建它的类如果设为私有)。这是一个很小的区别,但这确实意味着您可以帮助确保内部类不会在其他地方意外重新创建。

此外,使用匿名内部类会使任何人阅读您的代码更加困难,因为他们必须解析这个不知从何而来的类。使用命名的内部类,您可以更多地组织源代码。

我见过有两个(或更多)匿名内部类具有完全相同代码的情况。特别是在 GUI 中(您可能有多个控件执行相同的操作),这可能会突然出现(我说的是生产代码,而不是我的学生编写的代码)。

可读性问题是双向的,有些人发现匿名内部类更好,因为它可以让你看到一个地方发生了什么,而另一些人则认为它会分散注意力。这部分归结为个人喜好。

同样使类静态更有效,如果您在实例中声明匿名内部类,那么将会有更多开销,如果您不需要访问实例变量,这是浪费的(但可能不值得担心直到它出现问题)。

我个人的偏好是使用非匿名类,因为它们在以后修改代码时允许更大的灵活性。

于 2009-04-03T16:41:59.980 回答
10

为什么需要对它进行子类化?如果只是覆盖现有的虚方法,我觉得匿名内部类是可以的。如果您要添加额外的功能,我会使用命名类。不过,我会将其设为嵌套类(即使用static修饰符)-我发现它们更容易推理:)

于 2009-04-03T16:11:16.403 回答
8

做可能可行的最简单的事情:使用匿名内部类。

如果您后来发现需要更广泛的范围,请重构代码以支持这一点。

(你可以对变量做同样的事情——把它们放在最具体的范围内。对其他源资产做同样的事情是有意义的。)

于 2009-04-03T18:37:54.523 回答
4

匿名内部类很难在 Eclipse 中调试(这就是我使用的)。您将无法通过简单的右键单击来查看变量值/注入值。

于 2009-04-03T16:30:49.790 回答
3

我个人的经验法则:如果匿名内部类要小,请坚持使用匿名类。小被定义为大约 20 - 30 行或更少。如果它会更长,我认为它开始变得不可读,所以我将它命名为内部类。我记得曾经看过一个 4000+ 行的匿名内部类。

于 2009-07-30T18:55:23.493 回答
3

内部类的一个缺点是它们不能是静态的。这意味着它将持有对包含它们的外部类的引用。

非静态内部类可能是一个问题。例如,我们最近有一个内部类被序列化,但外部类不可序列化。隐藏的引用意味着外部类也将被序列化,这当然失败了,但需要一段时间才能找出原因。

在我工作的地方,我们的编码最佳实践(在可能的情况下)鼓励静态内部类,因为它们携带的隐藏包袱更少并且更精简。

于 2009-04-03T17:11:21.190 回答
2

匿名内部类通常是要走的路。我发现它们非常具有可读性。但是,如果该类的实例需要序列化(即使只是因为它是其他东西的字段),我强烈建议使用命名内部类。字节码中匿名内部类的名称很容易更改,这可能会破坏序列化。

于 2009-04-03T16:35:38.590 回答
2

匿名类不能有构造函数,因为它们没有名字。如果您需要传递其他变量而不是您要扩展的类的构造函数中的变量,则应使用(静态)命名的内部类。这有时可以通过在周围的方法/代码中使用最终变量来克服,但这有点难看恕我直言(并且可能导致 Robin 所说的)。

于 2010-11-20T04:15:44.293 回答
1

我对简单的匿名类没有问题。但如果它由多于几行代码或几个方法组成,内部类就更清晰了。我还认为,在某些情况下,它们永远不应该被使用。比如当他们必须返回数据时。

我看过代码,其中使用 1 个项目的最终数组将数据从调用传递回匿名内部类。在 anon 类的方法中,设置单个元素,然后在方法完成后提取此“结果”。有效但丑陋的代码。

于 2009-04-03T18:24:35.163 回答
1

匿名类:

  • 定义中不能有任何东西static(静态类、静态字段、静态初始化器等)
  • 无法在 Eclipse 中检查字段
  • 不能用作类型(Foo$1 myFoo=new Foo$1(){int x=0;}不起作用)
  • 无法使用 Eclipse 中的类名定位(搜索对Foo$1我不起作用)
  • 不能重复使用

然而,匿名类可以有一个初始化器,比如{super.foo(finalVariable+this.bar);}

命名内部类没有这些限制,但即使一个专门用于一个长过程的中间,声明也必须向上移动到下一个命名类。

如果限制不适用,我个人更喜欢匿名内部类,因为:

  • 我知道任何其他字段仅在类定义中引用。
  • Eclipse 可以轻松地将它们转换为嵌套类。
  • 我不需要复制我想使用的变量。我可以将它们声明为最终并引用它们。当我有很多参数时,这特别有用。
  • 交互的代码紧密相连。
于 2012-05-26T21:01:06.607 回答
0

今天刚和我的同事讨论过这个问题,正在四处寻找流行的意见。

我同意 TofuBeer。如果您的代码超过 2 行,它可能不是“一次性的”,并且可能有一天会被重用。如果您使用 MVC 模式创建表单,则页面上可能有 20 个可控制元素,而不是用大量匿名类使视图混乱(见鬼,您的视图可能是使用 GUI 构建器创建的,并且代码是自动生成的编辑源甚至不是一个选项)您可能会将每个元素提供给控制器。您可以在控制器中嵌套内部类以处理视图所需的每个不同的处理程序/侦听器接口。这很好地组织了代码,特别是如果您有一个约定,即您的处理程序类必须使用 GUI 元素名称命名(如 backButtonHandler 用于 backButtonElement)。这对我们非常有效,我们编写了一个自动注册工具(当您在视图上注册控制器时,视图会使用元素名称查找内部类并将它们用于每个命名元素的处理程序)。这对于匿名类是不可能的,并且使控制器更易于回收。

TLDR:如有疑问,请编写一个命名的内部类。您永远不会知道有一天是否有人想重用您的代码(除非它是 2 行代码,否则您必须想知道“这段代码有味道吗?”)。从长远来看,组织良好的代码具有更高的好处,尤其是在您的项目处于维护状态时。

于 2013-04-16T22:23:40.987 回答
0

我认为这是一个品味问题。我更喜欢对Functors使用匿名类。但在你的情况下,我会使用一个内部类,因为我认为你将在其中打包不仅仅是几行代码,也许不仅仅是一个方法。它会强调这样一个事实,即通过将其放在类中而不是隐藏在方法中的某个位置,它正在向超类添加功能。另外,谁知道呢,也许有一天你可能需要其他地方的子类。当然,这取决于您对软件将如何发展的了解程度。除此之外,只需掷硬币。:)

于 2009-04-03T16:24:28.947 回答
0

我认为在这种情况下你所做的一切都非常有意义,无论你怎么看,我认为你真的在为这个特殊问题而烦恼。它们都非常相似,并且都可以工作。

于 2009-04-03T16:11:38.073 回答
0

使用匿名内部类,我们无法更改包含类成员的状态。他们需要被宣布为最终的。

于 2016-02-27T12:18:12.123 回答