Hi all,
I've some confusion over how the static method is called. Please have a look at following code:
class A{
publicstaticvoid abc{
........
}
}
publicclass B extends A{
publicstaticvoid main(String a[]){
A refA = new B();
refA.abc(); //This will call class A's static method.
B refB = new B();
refA.abc(); //This will call class B's static method.
new B().abc(); //This will call class B's static method.
}
publicstaticvoid abc{
........
}
}
Now as they say 'Static method should be accessed in static way', which i think means using the class name and without creating any object. As we can see in above code, can we say that the static method checks for the reference variable and not the object while making a call. If it is so, then why does it allow to make a call on object(new B().abc())???
I'd appreciate if anyone could help me with the same?
Rocksolid99 wrote:
Now as they say 'Static method should be accessed in static way', which i think means using the class name and without creating any object. As we can see in above code, can we say that the static method checks for the reference variable and not the object while making a call. If it is so, then why does it allow to make a call on object(new B().abc())???
I'd appreciate if anyone could help me with the same?
It's less that "it uses the reference variable" and more that it "uses the inferred type." For instance, try:
((B)refA).abc();
I haven't tested it, but I'd guess it would call B.abc() since you're casting, even though the reference variable is an A.
When you do a new B(), it has an inferred type of B.
But yes, a good example of why to never reference a static member through a reference.
Hey endaisl,
Thanks for your time. But i am still not there.
When we say something like;
((B)refA).abc();
Aren't we just downgrading the refA here. And hence creating a virtual reference of Class B? If this is true, can't we say that the calling to static methods is done with ref variable?
Please let me know if i am missing out on something here.
It would be great if you could throw some more light on 'inferred' thing. What exactly is that?
Rocksolid99 wrote:
Hi all,
I've some confusion over how the static method is called. Please have a look at following code:
class A{
publicstaticvoid abc{
........
}
}
publicclass B extends A{
publicstaticvoid main(String a[]){
A refA = null;
refA.abc(); //This will call class A's static method.
B refB = null;
refB.abc(); //This will call class B's static method.
new B().abc(); //This will call class B's static method.
}
publicstaticvoid abc{
........
}
}
can't we say that the calling to static methods is done with ref variable
This is a compile time decision. In the bytecode call to the static method the variable is completely ignored. So all that matters is what's true about the type of the reference at compile time. The value of the variable is completely irrelevant.
Rocksolid99 wrote:
Hey endaisl,
Thanks for your time. But i am still not there.
When we say something like;
((B)refA).abc();
Aren't we just downgrading the refA here. And hence creating a virtual reference of Class B? If this is true, can't we say that the calling to static methods is done with ref variable?
The compiler recognises that it's a static method, and replaces your reference with a reference to the class upon which the static method is declared. Try it. Run it through a decompiler.
Rocksolid99 wrote:
It would be great if you could throw some more light on 'inferred' thing. What exactly is that?
It was probably a mistake to use that terminology, since inferred type already has a very different meaning in dynamically-typed languages. What I meant was that the Java compiler infers the type of an expression, and uses that to replace the static call.
Here's a fun one. What do you think will be printed from this code?
publicclass StaticMethod {
publicstaticvoid main(String[] args) {
(true ? new Concrete1() : new Concrete2()).print();
}
}
class Base {
publicstaticvoid print() {
System.out.println("Base");
}
}
class Concrete1 extends Base {
publicstaticvoid print() {
System.out.println("Concrete1");
}
}
class Concrete2 extends Base {
publicstaticvoid print() {
System.out.println("Concrete2");
}
}
What about if Concrete2 extended Concrete1 instead?
Then it gets really messy if StaticMethod is defined in a different source file, Concrete2 is changed to extend Concrete1, but only Concrete2's source file was recompiled. Then StaticMethod will likely continue printing "Base", but then when you recompile StaticMethod (even though you made no change) it will afterward print "Concrete1".
There's really no excuse not to just completely avoid this mess and always use the classname explicitly. Personally, it strikes me as odd that the Java language designers even allowed a static invocation from a non-static context. It's just opening the door to confusion and danger.
My guess why thy allow this: refactoring a method from instance to static would not break calling code.
Why refactor? Perhaps because you find out that no object state is involved, so you might as well make it static.
I don't say it's good or bad, just trying to guess why.
$ javac Class1.java Class2.java
$ java Class2
Hello, world!
$ vim Class1.java #at this point I edit method() to be static
$ javac Class1.java
$ java Class2
Exception in thread "main" java.lang.IncompatibleClassChangeError: Expecting non-static method
Class1.method()V
at Class2.main(Class2.java:5)
$ javac Class2.java
$ java Class2
Hello, world!
In other words, the compiled Class2 is expecting an instance method. You can't change one without at the very least recompiling the other. So the calling code breaks.