Вопрос-ответ

Why isn't calling a static method by way of an instance an error for the Java compiler?

Почему вызов статического метода через экземпляр не является ошибкой для компилятора Java?

Я уверен, что вы все знаете поведение, которое я имею в виду - такой код, как:

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

выдает предупреждение компилятора. Почему это не ошибка?

Редактировать:

Для ясности: вопрос не имеет ничего общего с потоками. Я понимаю, что при обсуждении этого часто приводятся примеры потоков из-за возможности действительно все испортить с ними. Но на самом деле проблема в том, что такое использование всегда бессмысленно, и вы не можете (грамотно) написать такой вызов и иметь это в виду. Любой пример вызова метода такого типа был бы сумасшедшим. Вот еще один:

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.SomeMethod() я ожидаю, что он будет использовать значение someVariable. Если SomeMethod() это статический метод, то это ожидание неверно; код обманывает меня. Как это может быть хорошо?

Как ни странно, Java не позволяет использовать потенциально неинициализированную переменную для вызова статического метода, несмотря на тот факт, что единственная информация, которую он собирается использовать, - это объявленный тип переменной. Это непоследовательный и бесполезный беспорядок. Зачем это разрешать?

ПРАВКА: Эта правка является ответом на ответ Клейтона, в котором утверждается, что он допускает наследование статических методов. Это не так. Статические методы просто не полиморфны. Вот короткая, но полная программа, демонстрирующая это:

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()"
}
}

As you can see, the execution-time value of b is completely ignored.

Ответ 2

Why should it be an error? The instance has access to all the static methods. The static methods can't change the state of the instance (trying to is a compile error).

The problem with the well-known example that you give is very specific to threads, not static method calls. It looks as though you're getting the activeCount() for the thread referred to by thread, but you're really getting the count for the calling thread. This is a logical error that you as a programmer are making. Issuing a warning is the appropriate thing for the compiler to do in this case. It's up to you to heed the warning and fix your code.

EDIT: I realize that the syntax of the language is what's allowing you to write misleading code, but remember that the compiler and its warnings are part of the language too. The language allows you to do something that the compiler considers dubious, but it gives you the warning to make sure you're aware that it could cause problems.

Ответ 3

They cannot make it an error anymore, because of all the code that is already out there.

I am with you on that it should be an error.
Maybe there should be an option/profile for the compiler to upgrade some warnings to errors.

Update: When they introduced the assert keyword in 1.4, which has similar potential compatibility issues with old code, they made it available only if you explicitly set the source mode to "1.4". I suppose one could make a it an error in a new source mode "java 7". But I doubt they would do it, considering that all the hassle it would cause. As others have pointed out, it is not strictly necessary to prevent you from writing confusing code. And language changes to Java should be limited to the strictly necessary at this point.

Ответ 4

Short answer - the language allows it, so its not an error.

java