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

tmt*_*est 75 java methods static

我相信你们都知道我的意思 - 代码如下:

Thread thread = new Thread();
int activeCount = thread.activeCount();
Run Code Online (Sandbox Code Playgroud)

引发编译器警告.为什么不是错误?

编辑:

要明确:问题与Threads无关.我意识到在讨论这个问题时经常给出Thread示例,因为它们可能真的搞砸了它们.但问题确实是这样的使用总是无稽之谈,你不能(胜任地)写出这样的电话并且意味着它.这种类型的方法调用的任何例子都是barmy.这是另一个:

String hello = "hello";
String number123AsString = hello.valueOf(123);
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*eet 78

基本上我认为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()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么我认为这会产生误导?因为如果我查看代码,someVariable.SomeMethod()我希望它使用的值someVariable.如果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()"
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • @Jon:我进行了类似的测试并证实了你的发现.基于此,我同意Java允许从实例var调用静态方法是错误的.没有能力(正如我原先想的那样),但是混乱或错误的可能性增加了. (5认同)

Bil*_*ard 13

为什么会出错呢?该实例可以访问所有静态方法.静态方法不能改变实例的状态(努力一个编译错误).

您提供的众所周知的示例的问题非常特定于线程,而不是静态方法调用.它看起来好像你正在获取所activeCount()引用的线程thread,但你真的得到了调用线程的计数.这是程序员正在制作的逻辑错误.在这种情况下,编译器发出警告是适当的.由您来注意警告并修复您的代码.

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

  • 它与*instance*无关.唯一的是变量的*声明类型*.对于语言设计师IMO来说,这是一个可怕的,可怕的错误和错误. (9认同)
  • @Bill:这样说吧 - 如果Java*没有允许它,有人建议它*应该*允许它,你的反应是什么?你真的会赞成它吗?或者你会争辩(就像我一样)这是一个毫无意义的功能,不必要地允许误导代码? (4认同)
  • 我不买"编译时"的原因 - 很明显你是通过参考查找方法; 然后检查它是否静止需要多长时间?我认为将它视为语言设计错误更容易. (2认同)

Thi*_*ilo 9

它们不再是一个错误,因为已经存在的所有代码.

我和你在一起,这应该是一个错误.也许应该有一个选项/配置文件供编译器将某些警告升级为错误.

更新:当他们在1.4中引入assert关键字时,它与旧代码具有类似的潜在兼容性问题,只有在您明确将源模式设置为"1.4"时才使其可用.我想在新的源模式"java 7"中可能会出现错误.但我怀疑他们会这样做,考虑到它会造成的所有麻烦.正如其他人所指出的那样,并不是必须阻止您编写令人困惑的代码.Java的语言更改应限制在此时严格必要.


Pau*_*ams 6

简短的回答 - 语言允许它,所以它不是一个错误.