没有值的Java枚举和实用程序类与私有构造函数之间的区别
实用类的一个常见事情是给它们一个私有的构造函数 :
public final class UtilClass { private UtilClass() {} ... }
但不幸的是,一些工具不喜欢那个私人的构造函数。 他们可能会警告说,它从来没有在课堂上被调用,它没有被testing覆盖,该块不包含评论,等等。
如果你这样做,很多警告消失:
public enum UtilClass {; ... }
我的问题是:除了对未来开发者的无休止的仇恨外,在没有值的枚举和在Java中有私有构造函数的类之间有什么重要的区别?
请注意,我并不是问一个Java枚举与一个具有公共静态final字段的类的优点是什么? 。 我不是决定一个事物列表应该是一堆常量还是一个枚举,我决定把一堆函数放在一个无构造函数的类或一个无价值的枚举中。
另外请注意,我其实不想这样做。 我只是想把这些权衡作为一般语言知识的一部分。
例如,使用枚举来污染自动完成,像UtilClass.values()
这样的无用方法。 还有什么其他缺点? 上升空间?
一个好处是,你绝对保证,即使在课堂内部也不能创build任何实例。
缺点是这超出了枚举的通常意图。 但是,我们已经为使用枚举实现的单例执行此操作。
Joshua Bloch关于这样的单例的“Effective Java”也适用于实用类:
…你会得到一个铁定的保证,除了声明的常量之外,不存在任何实例。 JVM做出这个保证,你可以依靠它。
免责声明:我没有使用这种模式,我不推荐或反对它。
使用enum
实际上并不是一个枚举是丑陋和混乱。 我会说这是不够的。
“效用阶层”模式是完全合法的。 如果你的工具不喜欢它,这是工具的问题。
在实用类中的以下模式也提供了可以保证不存在实例的铁证:
public abstract class Util { private Util() { throw new Error(); } ... // static methods }
此外,你没有额外的不相关的静态方法,由枚举提供。
唯一的区别是,你仍然可以在你的类中调用构造函数:
public final class UtilityClass { public static final UtilityClass Instance = new UtilityClass(); private UtilityClass () {} public static int Foo (int a, int b) { return a+b; } }
但是既然你是这个类的devise者,那么破坏你自己的代码契约是没有任何意义的。
一般来说,我读过的大多数软件devise书都反对使用静态方法 。 除非它们是真正的效用方法:从某种意义上说,它们决不会要求任何状态。 即便如此,实现一个Singleton模式只是一个小小的努力,当时间到了,你可以为它分配状态:
public final class UtilityClass { public static final UtilityClass Instance = new UtilityClass(); private UtilityClass () {} public int Foo (int a, int b) { return a+b; } }
并用UtilityClass.Instance.Foo(2,5);
调用它UtilityClass.Instance.Foo(2,5);
。 稍后在编码过程中执行引入状态转换将会更困难。 因此静态方法很难维护。
实例有用的原因是,如果有一种情况下,它可以在很多模式中使用它们,例如,在某种情况下,它依赖于应该完成的任务,通过使用static
方法,可以减lessdynamic方法,因为Java不会“ t支持方法指针(出于很好的理由)。 因此非静态方法更加dynamic和有用。
此外,一些安全研究人员认为,使用static
修饰符分析代码比较困难,因为它们可以从任何地方访问,副作用也不太可预测(例如在自动安全分析工具中):假设您的类没有完全实现,那么您仍然可以分析这些字段以了解它可以访问哪些方法,从而分析可能的副作用(networking使用情况,文件IO …)。 这可以生成应该validation的每个class级的可能危险列表。 至less如果我理解我的一个研究人员的博士论文是正确的。 因此非静态方法允许更多的修饰符分析。
总而言之:Java是build立在面向对象编程的基础之上的。 这意味着编程人员使用“ c世界”,而解释器/运行时使用“实体世界”。 我同意这两个词之间有很多冲突。 但static
方法在很多/某些情况下是解决这种冲突的错误。