为什么通过实例调用静态方法不是 Java 编译器的错误?

2022-08-31 12:38:47

我相信你们都知道我所说的行为 - 代码如下:

Thread thread = new Thread();
int activeCount = thread.activeCount();

引发编译器警告。为什么这不是一个错误?

编辑:

需要明确的是:问题与线程无关。我意识到在讨论这个问题时经常会给出Thread的例子,因为有可能把它们搞砸。但真正的问题是,这样的用法总是无稽之谈,你不能(胜任地)写这样的电话并认真对待它。这种类型的方法调用的任何示例都是 barmy。这是另一个:

String hello = "hello";
String number123AsString = hello.valueOf(123);

这使得它看起来好像每个 String 实例都带有一个“String valueOf(int i)”方法。


答案 1

基本上,我相信Java设计人员在设计语言时犯了一个错误,并且由于涉及的兼容性问题而修复它为时已晚。是的,它可能导致非常误导性的代码。是的,你应该避免它。是的,您应该确保将 IDE 配置为将其视为错误(IMO)。如果您曾经自己设计过一种语言,请记住它作为避免:)

为了回应DJClayworth的观点,以下是C#中允许的内容:

public class Foo
{
    public static void Bar()
    {
    }
}

public class Abc
{
    public void Test()
    {
        // Static methods in the same class and base classes
        // (and outer classes) are available, with no
        // qualification
        Def();

        // Static methods in other classes are available via
        // the class name
        Foo.Bar();

        Abc abc = new Abc();

        // This would *not* be legal. It being legal has no benefit,
        // and just allows misleading code
        // abc.Def();
    }

    public static void Def()
    {
    }
}

为什么我认为它具有误导性?因为如果我看代码,我希望它使用 someVariable 的值。如果 是静态方法,则该期望无效;代码欺骗了我。这怎么可能是一件好事呢?someVariable.SomeMethod()SomeMethod()

奇怪的是,Java不允许你使用一个潜在的未初始化的变量来调用静态方法,尽管它将使用的唯一信息是变量的声明类型。这是一个不一致且无益的混乱。为什么允许它?

编辑:此编辑是对Clayton答案的回应,该答案声称它允许静态方法的继承。事实并非如此。静态方法不是多态的。这里有一个简短但完整的程序来证明这一点:

class Base
{
    static void foo()
    {
        System.out.println("Base.foo()");
    }
}

class Derived extends Base
{
    static void foo()
    {
        System.out.println("Derived.foo()");
    }
}

public class Test
{
    public static void main(String[] args)
    {
        Base b = new Derived();
        b.foo(); // Prints "Base.foo()"
        b = null;
        b.foo(); // Still prints "Base.foo()"
    }
}

如您所见,的执行时间值被完全忽略。b


答案 2

为什么它应该是一个错误?实例有权访问所有静态方法。静态方法无法更改实例的状态(尝试更改是编译错误)。

您给出的众所周知的示例的问题非常特定于线程,而不是静态方法调用。看起来好像您正在获取 所引用的线程,但实际上您正在获取调用线程的计数。这是你作为程序员所犯的逻辑错误。在这种情况下,发出警告是编译器应该执行的操作。由您来听从警告并修复代码。activeCount()thread

编辑:我意识到语言的语法是允许你编写误导性代码的原因,但请记住,编译器及其警告也是语言的一部分。该语言允许您执行编译器认为可疑的操作,但它会给您警告,以确保您知道它可能会导致问题。


推荐