Difference between shadowing & overriding?

Showing Answers 1 - 1 of 1 Answers

anirbanwdc

  • Jan 18th, 2007
 

 SHADOWING

Suppose you're reading some Java code, and you come across
something like this:

    class A {
        int A = 37;
        A() {
            int A = 47;
            A aref = new A() {
                int A = 57;
                void A() {}
            };
        }
    }

This usage is legal, but not necessarily desirable. In fact, it
raises an interesting question about how the Java programming
language specification treats conflicting names. There are
several terms used in this area to describe various cases:
shadowing, overriding, hiding, and obscuring. This tip looks at
an example of each of these.

First an important point needs to be made: just because the
Java programming language allows you to do something, it doesn't
always mean that it's a desirable thing to do. For example, it's
legal to say:

    class A {
        int A;
    }

in a program, but you probably shouldn't because it's confusing.
The best way to handle issues with conflicting names is to simply
avoid them as far as possible. For example, you can avoid many
problems if you follow a coding convention that specifies that
the first letter of a type name (such as "class A") should be
capitalized, while the first letter of a field name (such as
"int A") should be lowercase.

Now let's look at an example of shadowing:

    public class Shadow {
        int a;
        int b;
   
        // parameters a/b shadow instance variables a/b
   
        public Shadow(int a, int b) {
   
            // set parameter equal to itself
   
            a = a;
   
            // set instance variable b equal to parameter b
   
            this.b = b;
        }
   
        public static void main(String args[]) {
            Shadow s = new Shadow(37, 47);
            System.out.println("a = " + s.a);
            System.out.println("b = " + s.b);
        }
    }
   
When your run Shadow, you should see:

    a = 0
    b = 47
  
One place shadowing comes up is when you have field names and
parameter names that are the same, and you want to use the
parameters to set the fields:

    int a;

    public void f(int a) {
        a = a;
    }

This doesn't work, because the parameter "a" shadows the field "a",
that is, the parameter name blocks access via a simple name to the
field name. You can get around this problem by saying:

    this.a = a;

which means "set field a to parameter a". Whether this style of
usage is desirable or not depends on your particular biases; one
point in its favor is that you don't have to invent parameter names
like "a1" or "_a".

The second example is one that illustrates overriding:

    class A {
        void f() {
            System.out.println("A.f");
        }
    }
   
    public class Override extends A {
   
        // instance method f overrides instance method A.f
   
        void f() {
            System.out.println("Override.f");
        }
   
        void g() {
            // call Override.f
   
            f();
   
            // call A.f
   
            super.f();
        }
   
        public static void main(String args[]) {
            Override o = new Override();
            o.g();
        }
    }
   
When you run Override, you should see:

    Override.f
    A.f

In this example, the method Override.f overrides the method A.f.
If you have an object of type Override, and call f, Override.f
is called. However if you have an object of type A, A.f is called.
This approach is a standard part of object-oriented programming.
For example, java.lang.Object declares a hashCode method, but
subclasses, such as String, provide an overriding version of the
method. The overriding version is tailored to the particular type
of data represented by the class.

You can call the superclass method by using the notation:

    super.f();

The second example is one that illustrates overriding:

    class A {
        void f() {
            System.out.println("A.f");
        }
    }
   
    public class Override extends A {
   
        // instance method f overrides instance method A.f
   
        void f() {
            System.out.println("Override.f");
        }
   
        void g() {
            // call Override.f
   
            f();
   
            // call A.f
   
            super.f();
        }
   
        public static void main(String args[]) {
            Override o = new Override();
            o.g();
        }
    }
   
When you run Override, you should see:

    Override.f
    A.f

In this example, the method Override.f overrides the method A.f.
If you have an object of type Override, and call f, Override.f
is called. However if you have an object of type A, A.f is called.
This approach is a standard part of object-oriented programming.
For example, java.lang.Object declares a hashCode method, but
subclasses, such as String, provide an overriding version of the
method. The overriding version is tailored to the particular type
of data represented by the class.

You can call the superclass method by using the notation:

    super.f();

A third example is that of hiding:

    class A {
        static void f() {
            System.out.println("A.f");
        }
        void g() {
            System.out.println("A.g");
        }
    }
   
    public class Hide extends A {
        static void f() {
            System.out.println("Hide.f");
        }
        void g() {
            System.out.println("Hide.g");
        }
        public static void main(String args[]) {
            A aref = new Hide();
   
            // call A.f()
   
            aref.f();
   
            // call Hide.g()
   
            aref.g();
        }
    }

When you run Hide, you should see:

    A.f
    Hide.g

In this example, Hide.f hides A.f, and Hide.g overrides A.g.
One way of seeing the difference between hiding and overriding
is to note that overriding applies to regular instance methods;
the actual method that is called is determined at run time
based on the type of the object (a so-called "virtual function").
This sort of dynamic lookup does not happen for static methods
or for fields. For example, in this code:

    class A {
        int x = 37;
        void f() {
            System.out.println("A.f");
        }
    }
   
    public class Lookup extends A {
        int x = 47;
        void f() {
            System.out.println("Lookup.f");
        }
        public static void main(String args[]) {
            A aref = new Lookup();
   
            // call Lookup.f

            aref.f();

            // display A.x
   
            System.out.println(aref.x);
        }
    }

the method reference through "aref" results in Lookup.f being
called, but the field reference obtains A.x. Or to say it another
way, the actual class of an object determines which instance method
is called. But for fields, the type of the reference is used
(here it's aref, of type A). When you run Lookup, you should see:

    Lookup.f
    37

  Was this answer useful?  Yes

Give your answer:

If you think the above answer is not correct, Please select a reason and add your answer below.

 

Related Answered Questions

 

Related Open Questions