声明最终的静态方法是一个坏主意吗?

bra*_*zoo 37 java methods static final

我理解在这段代码中:

class Foo {
    public static void method() {
        System.out.println("in Foo");
    }
} 

class Bar extends Foo {
    public static void method() {
        System.out.println("in Bar");
    }
}
Run Code Online (Sandbox Code Playgroud)

..静态方法Bar'隐藏'声明的静态方法Foo,而不是在多态意义上覆盖它.

class Test {
    public static void main(String[] args) {
        Foo.method();
        Bar.method();
    }
}
Run Code Online (Sandbox Code Playgroud)

...将输出:

在Foo
in Bar

重新定义method()finalFoo将禁用的能力Bar,以隐藏它,并重新运行main()将输出:

在Foo
的Foo

(编辑:将方法标记为时编译失败final,并且仅在删除时再次运行Bar.method())

将静态方法声明为final有意或无意地重新定义方法的子类是否被认为是不好的做法?

(是对使用行为的一个很好的解释final..)

Gre*_*osz 37

我认为将static方法标记为不是不好的做法final.

正如您所发现的那样,final将阻止该方法被子类隐藏,这是非常好的消息.

你的发言让我很惊讶:

在Foo中重新定义method()作为final将禁用Bar隐藏它的能力,并重新运行main()将输出:

在Foo
的Foo

不,标志着该方法finalFoo将防止Bar从编译.至少在Eclipse中我得到:

线程"main"中的异常java.lang.Error:未解决的编译问题:无法覆盖Foo的最终方法

另外,我认为人们应该总是调用static方法使用类名来限定它们,即使在类本身内也是如此:

class Foo
{
  private static final void foo()
  {
    System.out.println("hollywood!");
  }

  public Foo()
  {
    foo();      // both compile
    Foo.foo();  // but I prefer this one
  }
}
Run Code Online (Sandbox Code Playgroud)


aku*_*uhn 31

静态方法是Java最令人困惑的功能之一.有最佳实践可以解决这个问题,并且所有静态方法final都是这些最佳实践之一!

静态方法的问题在于

  • 它们不是类方法,而是以类名为前缀的全局函数
  • 奇怪的是,它们被"继承"到了子类
  • 令人惊讶的是,它们不能被覆盖而是隐藏起来
  • 完全打破它们可以用一个实例作为接收器来调用它们

所以你应该

  • 总是把他们的班级称为接收者
  • 总是用声明类作为接收者来调用它们
  • 总是让他们(或宣布类) final

你应该

  • 永远不要用实例作为接收者来调用它们
  • 永远不要用它们的声明类的子类作为接收器来调用它们
  • 永远不要在子类中重新定义它们

 

注意:您的程序的第二个版本应该会出现编译错误.我认为你的IDE隐藏了这个事实!

  • Eclipse中的第一个Java警告是"对静态成员的非静态访问".启用它,只要您不小心使用带有实例接收器的静态方法,就会收到警告. (2认同)

Bal*_*usC 6

如果我有一个public static方法,那么它通常已经位于一个只有方法的所谓实用程序类中static.自我解释的例子是StringUtil,SqlUtil,IOUtil,等等.这些实用程序类本身已经声明final并提供了private构造函数.例如

public final class SomeUtil {

    private SomeUtil() {
        // Hide c'tor.
    }

    public static SomeObject doSomething(SomeObject argument1) {
        // ...
    }

    public static SomeObject doSomethingElse(SomeObject argument1) {
        // ...
    }

}
Run Code Online (Sandbox Code Playgroud)

这样你就无法覆盖它们.

如果你的不是实用类,那我就会质疑public修饰符的值.不应该private吗?不过只是将它移到某个实用程序类.不要用public static方法弄乱"普通"类.这样您也不需要标记它们final.

另一种情况是一种抽象工厂类,它通过public static方法返回self的具体实现.在这种情况下,标记方法完全有意义final,您不希望具体实现能够覆盖该方法.


mR_*_*r0g 5

通常对于实用程序类(仅具有静态方法的类),不希望使用继承。出于这个原因,您可能希望将该类定义为final,以防止其他类扩展它。这将否定在实用程序类方法上添加最终修饰符。