一个仅包含静态方法的类应该是抽象类吗?

10

我有一个类,提供一些静态的实用方法集合。

一方面,我不希望这个类可以被实例化。另一方面,我也不想传达这个信号:这个类应该被继承(虽然我认为这种情况不太可能发生)。

那么,这个类应该是抽象类吗?

8个回答

13

将该类声明为final,并将默认构造函数声明为private,不提供任何public构造函数。这样就没有人能够子类化它或创建该类的实例。


10
为了防止使用反射来实例化它,在构造函数中抛出 RuntimeException :D - Pshemo
1
当然,如果项目中有人试图实例化这样的类,那么该项目可能已经失败了,所以担心这些东西真的是浪费时间。 - rees
1
@mre 我的评论有点儿玩笑,但并不特别难懂。显然,你的世界是完全黑白分明的。 - rees

8
不要将其声明为abstract; 声明一个private构造函数,这样甚至是子类也不能实例化您的实用程序类。
您可以将类声明为final,尽管如果所有构造函数都是private,那么任何人都无法对其进行子类化。
借鉴Pshemo在另一个答案中的评论,可以在构造函数中抛出RuntimeException以防止反射的setAccessible方法在 AccessibleObject中允许实例化:
public class MyUtility
{
   private MyUtility()
   {
      throw new RuntimeException("Instantiation of MyUtility is not allowed!");
   }

   public static void utilityMethod()
   {
      // Your utility method here.
   }
}

3

虽然顶级类不能被声明为static,但是通过将默认构造函数声明为private,可以使该类对其他类不可实例化(实际上是“静态的”),从而达到与static类似的效果。


2

另一个版本的@mre答案

enum MyClass{
    ;//this semicolon indicates that this enum will have no instances

    //now you can put your methods
    public static void myMethod(){
        //...
    }
}

默认情况下,枚举是final的,并且其构造函数是私有的。此外,您无法使用反射创建其实例,因为它在Constructor#newInstance中检查您是否正在实例化枚举对象。


+1,开箱即用。但它在意外地使用枚举类型方面存在问题,这与“枚举”的含义不符。 - rees

1
除了所有其他调用来给类一个私有构造函数之外,您还应该将其设置为final,以便清楚地表明它不可能是子类化的。
public final class Utils
{
    // prevent accidental construction.
    private Utils() 
    {  
    } 

    public static void foo()
    { 
        //util code here
    }
}

1

类中包含的内容与其是否应该是抽象类无关。关键是:抽象类必须有另一个类扩展它(一个“具体”类);只有该具体类可以被实例化。

要防止它被扩展,请使用final

要防止它被实例化,请将构造函数设为private

请注意,在Java中,这些是不同的概念。


1
不,这是一个实用类。应该使用私有默认构造函数将其声明为final,以避免实例化。如果启用了checkstyle,则未执行此操作会收到警告。

1

真的,你不必做任何事情。不会发生任何不好的事情,也没有人会实例化/子类化你的类。


+1 同意。这是一个从未发生过的意外。这就像在沙漠中的一条无人驾驶的道路上设置护栏一样。 - rees
在一个完全平坦的沙漠中,如果汽车离开道路,不会发生任何不良后果。最坏的情况是,不必要地创建实例将导致性能(在绝大多数情况下,完全微不足道)的降低。我们肯定有更重要的事情要关心吧? - meriton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接