匿名与命名的内部类? – 最佳实践?
我有一个类,我们称之为LineGraph,它呈现一个线条图。 我需要inheritance它,但派生类只在一个地方使用,并耦合到使用它的类。 所以我正在使用一个内部类。
我看到两种方法来做到这一点:
匿名的内部类
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. } }
我不是匿名的内部类的粉丝,因为坦率地说,我认为它看起来真的很丑。 但是对于只在一个地方使用的子类来说,是一个命名的内部类的矫枉过正? 什么是公认的做法?
匿名内部类的一个优点是没有人可以在任何其他地方使用它,而命名的内部类可以使用(如果只有通过创build私人的类创build它)。 这是一个小小的区别,但这确实意味着你可以保护一个内部阶层不被意外地用在其他地方。
另外,使用匿名内部类可以让任何读你的代码的人都高枕无忧 – “这个类正在被使用,无处不在。 如果你看到一个命名的内部类,有人可能会认为它会在class级中的多个地方使用。
他们是非常相似的,所以这两点都不是一个改变游戏规则的人。 我只是认为这有助于澄清如果你使用匿名内部类一次性,并命名内部类多次使用类内。
(反对Daniel Lew)
匿名内部类的一个缺点是,没有人可以在任何地方使用它,而命名的内部类可以使用(如果只有通过创build私人的类创build它)。 这是一个小小的区别,但这确实意味着你可以帮助确保内部类不会在别处意外重现。
而且,使用匿名的内部类让任何人读取你的代码的时间更加困难,因为他们必须parsing这个不知从何而来的类。 使用一个命名的内部类,你可以组织更多的源。
我已经看到有两个(或更多)具有完全相同代码的匿名内部类的情况。 特别是在graphics用户界面(可能有多个控件执行相同操作)时,可能会出现这种情况(我正在谈论生产代码,而不是我的学生写的代码)。
可读性问题是双向的,有些人可以更好地发现匿名的内部类,因为它可以让你看到一旦发生了什么,而其他人则会发现它是一种分心。 这部分归结为个人喜好。
如果你在一个实例中声明了一个匿名的内部类,那么使得一个静态类更有效率,那么将会有更多的开销,如果你不需要访问实例variables,是浪费的(但可能不值得担心直到它出现问题)。
我的个人偏好是使用非匿名类,因为它们允许在稍后修改代码时具有更大的灵活性。
为什么你需要子类? 如果只是重写一个现有的虚拟方法,我认为一个匿名的内部类是可以的。 如果你添加额外的function,我会使用一个命名的类。 我会让它成为一个嵌套类(即与static
修改) – 我觉得他们更容易推理:)
做最简单的事情,可能工作 :使用匿名内部类。
如果您以后发现需要更广泛的范围,请重构代码以支持此操作。
(你可以用variables来做同样的事情 – 把它们放在最具体的范围内,对其他源资源也是这样做的。
在Eclipse中匿名内部类很难debugging(多数民众赞成我使用)。 只需右键单击,就无法查看variables值/注入值。
内部类的一个缺点是它们不能是静态的。 这意味着它将持有对包含它们的外部类的引用。
非静态的内部类可能是一个问题。 例如,我们最近有一个内部类被序列化,但外部类是不可序列化的。 隐藏的引用意味着外部类也会被序列化,这当然是失败的,但是花了一段时间才发现原因。
在我工作的地方,我们的编码最佳实践(如果可能的话)鼓励静态的内部课程,因为它们携带的行李更less,而且更精简。
我个人的经验法则:如果匿名内部class级规模小,坚持一个匿名class级。 小被定义为大约20 – 30行或更less。 如果时间更长,我认为这个问题开始变得难以理解,所以我把它命名为内部class。 我记得有一次看到4000多行匿名内部类。
匿名的内部类通常是要走的路。 我发现他们非常可读。 但是,如果该类的实例需要序列化(即使只是因为它是一个其他字段),我强烈build议使用命名的内部类。 字节码中的匿名内部类的名称可以很容易地改变,这可以破坏序列化。
匿名类不能有一个构造函数,因为它们没有名字。 如果您需要传递其他variables,而不是您正在扩展的类的构造函数中的variables,则应使用(静态)名为inner的内部类。 这有时可以通过在周围的方法/代码中使用最终variables来克服,但是这有点丑陋(可能会导致Robin所说的)。
我对简单的匿名类没有问题。 但是,如果它由多行代码或几个方法组成,则内部类更清晰。 我也认为在一定的条件下,绝对不能使用。 比如何时必须返回数据。
我已经看到代码,其中最后一个数组的项目被用来传递数据从一个调用匿名内部类。 在anon类的方法中,设置单个元素,然后在方法完成后提取这个“结果”。 有效的,但丑陋的代码。
匿名课程:
- 在定义(静态类,静态字段,静态初始化器等)中不能有任何
static
的东西, - 在Eclipse中不能检查字段
- 不能用作types(
Foo$1 myFoo=new Foo$1(){int x=0;}
不起作用) - 不能在Eclipse中使用类名查找(search
Foo$1
不适用于我) - 不能重复使用
但是,匿名类可以有一个初始化程序,如{super.foo(finalVariable+this.bar);}
命名的内部类没有这些限制,但是即使在一个长的过程中只使用一个,声明也必须移动到下一个命名的类。
我个人更喜欢匿名内部类,如果限制不适用,因为:
- 我知道任何额外的字段只在类定义中引用。
- Eclipse可以轻松地将它们转换为嵌套类。
- 我不需要复制我想要使用的variables。 我可以直接宣布他们并引用他们。 当我有很多参数时,这是特别有用的。
- 交互的代码靠得很近。
我认为,在这种情况下,你所做的事情是完全合理的,无论你如何看待这个问题,我认为你真的是在分析这个问题。 他们是如此相似,或者会工作。
我认为这是一个品味的问题。 我更喜欢用Functors的匿名类。 但在你的情况下,我会使用一个内部类,因为我认为你会打包不仅仅是几行代码,也许不仅仅是一个方法。 它会强调这样的事实:它将超类的function添加到类中,而不是隐藏在方法的某个地方。 另外,谁知道,也许有一天你可能需要其他的子类。 当然,这取决于你对软件的演变有多了解。 除此之外,只要翻转一个硬币。 🙂
今天刚刚和我的同事进行了这个讨论,并正在挖掘民意。
我同意豆腐啤酒。 如果你的代码有两行以上,那么可能不是一次性的,有可能在某一天被重新使用。 如果您使用MVC模式创build表单,则可能在页面上有20个可控元素,而不是使用大量匿名类来混淆视图(您的视图可能是使用GUI构build器创build的,代码是自动生成的编辑源甚至没有一个选项),你可能会将每个元素提供给控制器。 您可以在控制器中嵌套内部类来处理您的视图所需的每个不同的处理程序/侦听器接口。 这很好地组织代码,特别是如果你有一个约定,你的处理程序类必须使用GUI元素名称(例如backButtonElement的backButtonHandler)来命名。 这对我们非常有用,我们编写了一个自动注册工具(当你在一个视图上注册一个控制器时,视图使用元素名称查找内部类,并将它们用于每个指定元素上的处理程序)。 这对于匿名类是不可能的,并且使控制器更加可回收。
TLDR:当有疑问时写一个命名的内部类。 你永远不会知道某人是否有一天想重新使用你的代码(除非是两行代码,那么你不得不怀疑这个代码是否有味道?)。 从长远来看,组织良好的代码有很多好处,特别是当你的项目进行维护时。
对于匿名内部类,我们不能改变包含类成员的状态。 他们需要被宣布为最终的。