Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'm sure you all know the behaviour I mean - code such as:

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

provokes a compiler warning. Why isn't it an error?

EDIT:

To be clear: question has nothing to do with Threads. I realise Thread examples are often given when discussing this because of the potential to really mess things up with them. But really the problem is that such usage is always nonsense and you can't (competently) write such a call and mean it. Any example of this type of method call would be barmy. Here's another:

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

Which makes it look as if each String instance comes with a "String valueOf(int i)" method.

like image 627
tmtest Avatar asked Mar 04 '09 13:03

tmtest


People also ask

Can you call a static method from an instance Java?

Java syntax allows calling static methods from an instance. For example, we could create this code and it would compile and run correctly: public static void main(String args) { Example ex = new Example();

Why can a static method not refer to an instance variable?

A static method cannot access a class's instance variables and instance methods, because a static method can be called even when no objects of the class have been instantiated. For the same reason, the this reference cannot be used in a static method.

Can a static method be called from an instance method?

In order to call an instance method, you need an instance. So a static method can call an instance method as long as it has a reference to an instance to call it on.

Why can't static methods call the instance methods present in the same class?

Within a static method, you do not have an instance of the class. So it will be impossible to call an instance method on an instance when no instance exists.


2 Answers

Basically I believe the Java designers made a mistake when they designed the language, and it's too late to fix it due to the compatibility issues involved. Yes, it can lead to very misleading code. Yes, you should avoid it. Yes, you should make sure your IDE is configured to treat it as an error, IMO. Should you ever design a language yourself, bear it in mind as an example of the kind of thing to avoid :)

Just to respond to DJClayworth's point, here's what's allowed in 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()     {     } } 

Why do I think it's misleading? Because if I look at code someVariable.SomeMethod() I expect it to use the value of someVariable. If SomeMethod() is a static method, that expectation is invalid; the code is tricking me. How can that possibly be a good thing?

Bizarrely enough, Java won't let you use a potentially uninitialized variable to call a static method, despite the fact that the only information it's going to use is the declared type of the variable. It's an inconsistent and unhelpful mess. Why allow it?

EDIT: This edit is a response to Clayton's answer, which claims it allows inheritance for static methods. It doesn't. Static methods just aren't polymorphic. Here's a short but complete program to demonstrate that:

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.

like image 62
Jon Skeet Avatar answered Oct 14 '22 02:10

Jon Skeet


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.

like image 40
Bill the Lizard Avatar answered Oct 14 '22 01:10

Bill the Lizard