Static methods overridden !!

R

Ravi

Hi,

Consider the following piece of code

class AnimalTest {
public static void saySomething() {
System.out.println(" AnimalTest!");
}
}

class CowTest extends AnimalTest {
public static void saySomething1() {
System.out.println(" CowTest!");
}

public static void main(String[] args) {
AnimalTest[] animals = { new AnimalTest(), new CowTest() };
for (AnimalTest a : animals) {
a.saySomething();
}
new CowTest().saySomething();
}
}

Interestingly it prints out AnimalTest! thrice. I am wondering how did
it compile as CowTest doesn't have the method saySomething. Does the
static method got carried over to the subclass??

Regards,
Ravi
 
D

Daniel Pitts

Hi,

Consider the following piece of code

class AnimalTest {
public static void saySomething() {
System.out.println(" AnimalTest!");
}

}

class CowTest extends AnimalTest {
public static void saySomething1() {
System.out.println(" CowTest!");
}

public static void main(String[] args) {
AnimalTest[] animals = { new AnimalTest(), new CowTest() };
for (AnimalTest a : animals) {
a.saySomething();
}
new CowTest().saySomething();
}

}

Interestingly it prints out AnimalTest! thrice. I am wondering how did
it compile as CowTest doesn't have the method saySomething. Does the
static method got carried over to the subclass??

Regards,
Ravi

Static methods are Class level, so it doesn't matter WHAT object type
you have.

As a matter of fact, the following WILL work.

CowTest ct = null;
ct.saySomething();

Static calls are really replaced by CowTest.saySomething() (which it
inherits from AnimalTest)

Hope this helps,
Daniel.
 
R

Ravi

Static calls are really replaced by CowTest.saySomething() (which it
inherits from AnimalTest)

Yep, I understand that Static method calls are at class level than at
object level. But, are you trying to say that static methods will be
inherited but not overridden? This is strange and confusing. Can you
please try n explain from JVM point of view? Thanks.
 
E

Eric Sosman

Ravi said:
Yep, I understand that Static method calls are at class level than at
object level. But, are you trying to say that static methods will be
inherited but not overridden? This is strange and confusing. Can you
please try n explain from JVM point of view? Thanks.

Will you accept an explanation that's not from the JVM
point of view, but from the Java language point of view?

Static methods can't be overridden, because there's no
polymorphism involved. For instance methods, the choice of
which method is called depends on the actual class of the
object that is referenced -- on the `this', if you like:

Object thing = "Hello, world!";
System.out.println(thing.toString()); // String's method
thing = new File("forty.two");
System.out.println(thing.toString()); // File's method

But with static methods there is no `this' to determine
which method to call. You write Classname.doit(42), and
as expected you call the static doit() method of the class
Classname. Observe that in this form there is *no* object
instance to govern the selection of different doit() methods;
you will always and only get the doit() of Classname, and not
some other class' doit().

The confusion arises when you don't write the class name,
but instead use a reference variable: thing.doit(42). Many
people find it odd that Java even permits this form, and some
go so far as to call it a flaw in the language (I'm not enough
of a connoisseur to have an opinion), but for reasons good or
bad the form is legal. But it still doesn't mean that Java
checks the class of the object `thing' refers to to decide
which doit() to call; Java calls the doit() method of the class
that matches the declared type of the `thing' reference. Indeed,
as Daniel Pitts pointed out, `thing' need not even be a valid
object reference at all:

Classname thing = null;
thing.doit(42); // Classname's method

You can explore this a little more by making a few simple
alterations to your original code sample, coming up with
something like

class Animal {

public static void main(String[] unused) {
Animal[] zoo = {
new Animal(), new Dog(), new Beagle(), null };
for (Animal a : zoo) {
System.out.println(a.getName());
}
}

static String getName() { return "Animal"; }
}
class Dog extends Animal {
static String getName() { return "Dog"; }
}
class Beagle extends Dog {
static String getName() { return "Beagle"; }
}

What output do you expect? What would you expect if the
final three `static' keywords were removed? Make your
predictions, then try it both ways and see.
 
R

Ravi

Thanks Eric for elaborate explanation on static method calls.
Will you accept an explanation that's not from the JVM
point of view, but from the Java language point of view?
Not a problem :)
Java calls the doit() method of the class
that matches the declared type of the `thing' reference.

Well, the class doesn't have the method at all ! Please refer the
original code again. CowTest class doesn't have saySomething method at
all . It has saySomething1 (1 (one) extra in the end, may be I should
have made this more clearly differentiating). I am not referring the
objects here and I am clear on the fact that objects have nothing to
do with invocation of static methods.

you can replace new CowTest().saySomething(); with
CowTest.saySomething(); if it makes things simpler.

Clearly saySomething comes from super class. This is confusing for
me.

Regards,
Ravi
 
L

Lew

Ravi said:
Clearly saySomething comes from super class. This is confusing for
me.

The method-resolution mechanism moves up the inheritance hierarchy from the
compile-time type to look for the first matching method at runtime. Since
CowTest "is-an" AnimalTest, the invocation from CowTest can find the method in
AnimalTest.

However, if CowTest did have a matching static method, it wouldn't override
the superclass static method, it would hide the superclass static method.
There is no polymorphism of static methods.

AnimalTest.saySomething() will never invoke CowTest.saySomething().

-- Lew
 
J

Joshua Cranmer

Ravi said:
Well, the class doesn't have the method at all ! Please refer the
original code again. CowTest class doesn't have saySomething method at
all . It has saySomething1 (1 (one) extra in the end, may be I should
have made this more clearly differentiating). I am not referring the
objects here and I am clear on the fact that objects have nothing to
do with invocation of static methods.

you can replace new CowTest().saySomething(); with
CowTest.saySomething(); if it makes things simpler. Yes.

Clearly saySomething comes from super class. This is confusing for
me.

Regards,
Ravi

What is going in is that the compiler is determining /at compile time/
what the method to be called is, based on the declaration of the
variable. For example, this will not compile:

Object foo = new AnimalTest();
foo.saySomething();

because method Object does not have a method 'saySomething'. The
compiler is using the declaration of the variable (Object in my example,
AnimalTest in yours) to determine what static method to call. At no
point does the actual type come into play. For example, this:

((AnimalTest)new Object()).saySomething();

will compile and is equivalent to this:

AnimalTest.saySomething();

even though it would throw a ClassCastException if it were an instance
method, like so:

class Foo {
public void bar() {}
public static void main(String[] args) {
((Foo)new Object()).bar();
}
}

Hope this helps.
 
L

Lew

The method-resolution mechanism moves up the inheritance hierarchy from the
compile-time type to look for the first matching method. Since CowTest "is-an"
AnimalTest, the invocation from CowTest can find the method in AnimalTest.

However, if CowTest did have a matching static method, it wouldn't override
the superclass static method, it would hide the superclass static method.
There is no polymorphism of static methods.

AnimalTest.saySomething() will never invoke CowTest.saySomething().

-- Lew
 
R

Ravi

The method-resolution mechanism moves up the inheritance hierarchy from the
compile-time type to look for the first matching method. Since CowTest "is-an"
AnimalTest, the invocation from CowTest can find the method in AnimalTest.

However, if CowTest did have a matching static method, it wouldn't override
the superclass static method, it would hide the superclass static method.
There is no polymorphism of static methods.

My understanding of overriding is as follows. (Not polymorphism , just
sticking to overriding)

Class Super {
public void method1(){}
}
Class DerivedOne extends Super {
}
Class DerivedTwo extends Super {
public void method1(){}
}

public Class OverrideDemo {
public static void main(String a[]) {
new DerivedOne().method1(); //calls the Super class method1()
new DerivedTwo().method1(); //calls the DerivedTwo class method1()
}
}

I am not talking about polymorphism here, just overriding. If you
observe carefully, then the behavioiur of statis methods is exactly
similar. Assume that the method1 is static.
DerivedOne.method1() ; //will call Super static method method1.
DerivedTwo.method2(); //will call DerivedTwo static method method1.

Technically speaking static methods ARE OVERRIDDEN, not at the object
level ofcourse at the class level as invocation of statics is not
object dependent. Also, we cannot take the advantage of polymorphism
in case of the static methods but thats not the point. Static methods
are overridden.

Does my argument make sense?

Regards,
Ravi
 
M

Michael Rauscher

Ravi said:
Technically speaking static methods ARE OVERRIDDEN, not at the object
level ofcourse at the class level as invocation of statics is not
object dependent. Also, we cannot take the advantage of polymorphism
in case of the static methods but thats not the point. Static methods
are overridden.

Speaking in terms of the JLS, static methods are hidden, not overriden.
See [1] for details.

Bye
Michael

[1]
<http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.8>
 
C

Chris Uppal

Ravi said:
I am not talking about polymorphism here, just overriding.

In Java overriding /is/ polymorphism. That's to say, the only use of the word
"overriding" that's allowed (if you want to talk be understood by other Java
programmers) is to mean the instance-side re-implementation of inherited
methods by subclasses (or in implementations of interfaces).

As you know, Java's static methods don't work like that, so the word
"overriding" is simply not applicable here.

Probably the best way to think about what's happening is to take it in steps.

[WARNING: the following is a simplified view, and is inaccurate in small ways
that I'll explain at the end of this post]

First off, as you also know, you can invoke any (public) static method from any
place by using the syntax:
fully.qualified.ClassName.staticMethod();

When it comes right down to it -- i.e. in terms of how the compiler treats
static methods -- that's the /only/ way to invoke a static method. But the
compiler does allow a number of convenient abbreviations.

One, which has already been discussed, is the ill-conceived idea that you can
replace the name of the class by some expression with the (statically
determined) type which is the name of the class.

Another abbreviation is that if you have an
import fully.qualified.ClassName;
or
fully.qualified.*;
statement in your Java source, then you can refer to the class by its short
name, and thus invoke the static method by the shorter expression:
ClassName.staticMethod();

Yet another abbreviation is that if the method name is "in scope" then you
don't need the class name at all, you can just write:
staticMethod();

Now, the concept of being in scope is interesting. It applies everywhere
within the body of the class where the static method is defined. And it /also/
applies throughout the bodies of any subclasses of that class. Hence, within a
subclass, you can also write
staticMethod();
and the name will be resolved to:
fully.qualified.ClassName.staticMethod();
at compile time (remember the above warning -- that assertion is technically
incorrect, although it does capture the /intended/ idea of what's happening).

A further refinement of the idea of scoping is that if you have a class, Super,
which defines a static method, aMethod(), and you have a subclass Sub, which
does /not/ define a method of the same name and signature, then you can invoke
Super.aMethod() with the method call expression:
Sub.aMethod();
And "aMethod" is resolved in the scope defined by Sub, which includes
Super.aMethod().

You /can/ call that "inheritance" if you like -- it's certainly not an abuse of
the word -- but it's important to realises that what is being inherited is the
just the scope in which names are resolved (at compile time). The kind of
inheritance we see here is completely different from the kind of polymorphic,
OO, inheritance which is used for (non-private, non-final) instance methods.
But there is no overriding involved at all (by definition of the word
"override" as it is used in Java).


All OK so far ? I hope so, because it's a reasonably simple picture, and it
does reflect how Java is intended to work and how we (as programmers) are
intended to think about it. If you aren't interested in details, then stop
reading now, because the rest of this post will just add confusion without
making you better able to understand ordinary Java code.


Right, I said that the above was technically inaccurate; here's how. I said
that the compiler statically fills in the name of the class when it expands the
abbreviation. That's true, but there are rules about /which/ class name it
fills in. You might expect it to look to see what class defines the method
(which it has to do anyway) and use the name of that class to expand the
abbreviation. In fact, it doesn't do that (although there were bugs in the
javac compiler in this area as late as JDK 1.3). When a programmer writes:
staticMethod();
the compiler uses the class where the method call is written to begin resolving
the name "staticMethod()", it will find the definition of that method in some
superclass, but it is not allowed to expand the abbreviation by naming that
superclass explicitly -- it is required (by the JLS) to expand it out to the
name of the class where the lookup /began/. In this case the name of the class
where the code which calls staticMethod() is defined. For instance, if you
have:

class fully.qualified.Super
{
static void aMethod() {}
}
class fully.qualified.Sub extends fully.qualified.Super
{
void someCode() { aMethod(); }
}
class my.Class
extends fully.qualified.Sub
{
}

and you create an instance of class my.Class, and call the (instance-side)
someCode() method that in inherits from fully.qualified.Sub, then the bytecode
which are executed will contain the equivalent of the Java code (after
expansion by the compiler):
fully.qualified.Sub.aMethod();
even though there is no such method as fully.qualified.Sub.aMethod() ! That is
surprising because it means that aMethod() is /actually/ resolved, at runtime,
by a search up the inheritance hierarchy[*], despite the fact that Java's
static classes are, according the language design, always resolved
/statically/. The is room for debate about why there is this odd anomaly in
the specification. One hypothesis is that the language designers were just
confused about static methods, and didn't really have a clear idea of what they
were trying to achieve. Another hypothesis is that it's all about supporting
binary compatibility[**] as classes evolve independently or each other. My own
opinion is that there's a bit of truth in both hypotheses, but that the second
one is a bit more true than the first ;-)

-- chris

[*] Obviously the JVM will optimise out that search -- there's no time penalty
at runtime.

[**] There is a large section of the JLS which is all about allowing class
files to work correctly even if they have been compiled against different
versions of the other classes they mention. Or, if not always /correctly/,
then at least with clearly defined behaviour, requirements, and guarantees.
See the JLS for details.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,187
Members
46,729
Latest member
ScarlettJe

Latest Threads

Top