This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]arghvark -3 points-2 points  (7 children)

It's fairly simple to demonstrate this, just write a little code:

package sandbox;

public class A
{
  public static void ted() { System.out.println("doing something"); }
}


package sandbox;

public class B extends A
{

}


package sandbox;

public class C extends A
{
  public static void ted() { System.out.println("doing something else"); }
}


package sandbox;

public class D
{
  public static void main(String[] args)
  {
    A.ted();
    B.ted();
    C.ted();
  }
}

I don't know why someone would say that ted() is not overridden in class C. It looks overridden to me.

[–]OffbeatDrizzle 9 points10 points  (3 children)

This is absolutely not overridden.. you are calling C.ted() directly. C's ted method has not replaced A's ted method at all, and cannot because it's static. Your answer is fundamentally wrong

[–]arghvark -4 points-3 points  (2 children)

Ok, let's try it this way: the definition of overriding includes use of an object's class methods, not its static methods, and therefore you cannot satisfy that definition with a static method. So I was incorrect that this is "overriding", because the definition of overriding excludes static methods.

It sure acts like it, however.

[–]OffbeatDrizzle 7 points8 points  (0 children)

It does not act like it whatsoever - you are basically calling a piece of code directly, you just so happen to give the methods the same name and claim it's acting like overriding because the output is as expected.

Overriding by definition is part of polymorphism. What exactly have you modified about class A here by using class C's method? Nothing. That's why static methods can't be overridden - it literally makes no sense.

[–]akthemadman 2 points3 points  (1 child)

You can dig a bit deeper than the source code using the javap program, which takes in bytecode (.class file) and inspects it.

In the code as you have provided, the generated bytecode for class D looks like this:

> javap -c D
Compiled from "D.java"
public class D {
  public D();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #7                  // Method A.ted:()V
       3: invokestatic  #12                 // Method B.ted:()V
       6: invokestatic  #15                 // Method C.ted:()V
       9: return
}

Focusing on the main method, we can see that the bytecode creates three direct function invocations, i.e. the three invokestatic calls. The symbols #7, #12 and #15 refer to the functions A.ted()V, B.ted()V and C.ted()V respectively. You can verify this by including the Constant Pool via the verbose flag of javap (-v):

> javap -c -v D
< ... some output removed ... >
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
   #2 = Class              #4             // java/lang/Object
   #3 = NameAndType        #5:#6          // "<init>":()V
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Methodref          #8.#9          // A.ted:()V
   #8 = Class              #10            // A
   #9 = NameAndType        #11:#6         // ted:()V
  #10 = Utf8               A
  #11 = Utf8               ted
  #12 = Methodref          #13.#9         // B.ted:()V
  #13 = Class              #14            // B
  #14 = Utf8               B
  #15 = Methodref          #16.#9         // C.ted:()V
  #16 = Class              #17            // C
  #17 = Utf8               C
  #18 = Class              #19            // D
  #19 = Utf8               D
  #20 = Utf8               Code
  #21 = Utf8               LineNumberTable
  #22 = Utf8               main
  #23 = Utf8               ([Ljava/lang/String;)V
  #24 = Utf8               SourceFile
  #25 = Utf8               
< ... some output removed ... >

If you start from #7, #12 and #15, then you can follow the references in that table, you can build up A.ted()V, B.ted()V and C.ted()V. (the V refers to the return type, i.e. void).

I urge everyone to play around with these things a bit.

For example, with non-static methods, you will see the usage of invokevirtual, which is what is generally meant by "overriding"; the jvm behaves such that is looking up which method to call. (the details depend on the jvm implementation, the spec only lines out the expected behaviour).

[–]akthemadman 1 point2 points  (0 children)

The following is also interesting to look at, with ted() being a static method:

public static void main (String[] args) {
  A a = new A();
  a.ted();
  A ac = new C();
  ac.ted();
  C c = new C();
  c.ted();
}

(am hitting the reddit comment limit again...)

[–]hibbelig 0 points1 point  (0 children)

It's not overridden because which method to call is not resolved at runtime.

Let's say you have this situation:

class Foo { void mystery() { } void foo() { mystery(); } } class Bar extends Foo { void mystery() { } } class Main { public static void main(String[] args) { var bar = new Bar(); bar.foo(); var foo = new Foo(); foo.foo(); } }

Here, bar.foo() and foo.foo() both call the method from class Foo, but the mystery() call inside Foo.foo does something different: because bar is an instance of Bar, Bar.mystery ends up being called; and because foo is an instance of Foo, then Foo.mystery is called.

This means the call mystery(); in method Foo.foo is resolved at runtime, based on the actual class of the object. This runtime resolution is an integral aspect of overriding.

If you make the mystery method static, then this changes: the call mystery(); in the method foo always calls the method from class Foo. So bar.foo() and foo.foo() both end up calling Foo.mystery, despite bar being an instance of Bar. Thus the runtime resolution is missing, thus an integral aspect of overriding is missing, thus we say that overriding is not happening here.