Overriding VS Hiding Java - Confused

Overriding vs Hiding Java - Confused

Overriding basically supports late binding. Therefore, it's decided at run time which method will be called. It is for non-static methods.

Hiding is for all other members (static methods, instance members, static members). It is based on the early binding. More clearly, the method or member to be called or used is decided during compile time.

In your example, the first call, Animal.testClassMethod() is a call to a static method, hence it is pretty sure which method is going to be called.

In the second call, myAnimal.testInstanceMethod(), you call a non-static method. This is what you call run-time polymorphism. It is not decided until run time which method is to be called.

For further clarification, read Overriding Vs Hiding.

Java inheritance: What is the difference between method overriding and method hiding?

Hiding it means that you can't call super.method() in the sub class's implementation.

So for example

class Cat extends Animal {
public static void testClassMethod() {
super.testClassMethod(); //this is not possible
System.out.println("The static method in Cat");
}
public void testInstanceMethod() {
super.testInstanceMethod(); //this is fine
System.out.println("The instance method in Cat");
}

}

What's the difference between override and hidden in java?

Static members(methods and variables) will not be present in the sub class(Child class) object which inherit them but they'll be present as a single copy in the memory.

Static members can be accessed by the class name of both Super class and sub class but they are not physically present in the object of these classes.

Where as when you inherit non-static members, Sub class object in memory will contain both inherited methods as well as the methods of its own. So when you try to write a similar method here, super class method will be overridden. On the other hand as static methods does not participate in inheritance, any similar method you write that is present in super class, new method will run every-time it is asked for. Parent class method is just hidden but not overridden!

What is method hiding in Java? Even the JavaDoc explanation is confusing

public class Animal {
public static void foo() {
System.out.println("Animal");
}
}

public class Cat extends Animal {
public static void foo() { // hides Animal.foo()
System.out.println("Cat");
}
}

Here, Cat.foo() is said to hide Animal.foo(). Hiding does not work like overriding, because static methods are not polymorphic. So the following will happen:

Animal.foo(); // prints Animal
Cat.foo(); // prints Cat

Animal a = new Animal();
Animal b = new Cat();
Cat c = new Cat();
Animal d = null;

a.foo(); // should not be done. Prints Animal because the declared type of a is Animal
b.foo(); // should not be done. Prints Animal because the declared type of b is Animal
c.foo(); // should not be done. Prints Cat because the declared type of c is Cat
d.foo(); // should not be done. Prints Animal because the declared type of d is Animal

Calling static methods on instances rather than classes is a very bad practice, and should never be done.

Compare this with instance methods, which are polymorphic and are thus overridden. The method called depends on the concrete, runtime type of the object:

public class Animal {
public void foo() {
System.out.println("Animal");
}
}

public class Cat extends Animal {
public void foo() { // overrides Animal.foo()
System.out.println("Cat");
}
}

Then the following will happen:

Animal a = new Animal();
Animal b = new Cat();
Cat c = new Cat();
Animal d = null;

a.foo(); // prints Animal
b.foo(); // prints Cat
c.foo(); // prints Cat
d.foo(): // throws NullPointerException

is the text regarding overriding and hiding methods on docs.oracle.com ambiguous?

From my perspective it seems like that both static methods in both the superclass and subclass are hidden, and by early-binding (compile-time binding) the appropriate method is chosen and the other one is hidden.

For below, consider this code:

class SuperClass {
static void a() { System.out.println("SuperClass.a()"); }
static void b() { System.out.println("SuperClass.b()"); }
void testSuper() { // Call from "inside" SuperClass
a(); // calls SuperClass.a()
b(); // calls SuperClass.b()
}
}
class SubClass extends SuperClass {
static void b() { System.out.println("SubClass.b()"); }
static void c() { System.out.println("SubClass.c()"); }
void testSub() { // Call from "inside" SubClass
a(); // calls SuperClass.a().
b(); // calls SubClass.b().
c(); // calls SubClass.c()
}
}
class Test {
void testSuper() { // Call SuperClass from "outside"
SuperClass.a(); // calls SuperClass.a()
SuperClass.b(); // calls SuperClass.b()
}
void testSub() { // Call SubClass from "outside"
SubClass.a(); // calls SuperClass.a()
// IDE warning: The static method a() from the type SuperClass should be accessed directly
SubClass.b(); // calls SubClass.b()
SubClass.c(); // calls SubClass.c()
}
}

There are two cases to consider:

  • The two testSuper() methods: Calling a method from "inside" SuperClass, or calling a method from "outside" by qualifying with SuperClass.

    In this case, nothing is hidden. You can call a() and b() in SuperClass.

    The methods in SubClass are not considered hidden, because they are clearly not in scope.

  • The two testSub() methods: Calling a method from "inside" SubClass, or calling a method from "outside" by qualifying with SubClass.

    In this case, all 4 methods are in scope, but the b() method in SuperClass is hidden.

As you can see, only the b() in SuperClass is ever considered hidden. The b() in SubClass is never hidden.

Ruby hiding vs overriding

Java has three different kinds of "methods": instance methods, static methods and constructors. Ruby only has one: instance methods.

In Java, static methods must behave differently from instance methods, because classes aren't objects. They have no class, therefore no superclass, so there is nothing to override. In Ruby, classes are objects just like any other object, they have a class, which can have a superclass, and thus subclasses can override superclass methods.

Note: you may have heard about class methods or singleton methods in Ruby. That's a lie. Well, okay, not a lie. It's a convenient shorthand we use, because "class method" is easier to pronounce than "regular instance method of the class object's singleton class" … but that's precisely what it is. There are no class methods.

In Ruby, every object can have methods of its own. These are called "singleton methods". Classes are objects like any other object, so they can have singleton methods, too. When the object a singleton method belongs to is a class, we call that method a class method. But that's just what we call it, there is no difference between a class method and a singleton method.

Actually, in Ruby, every object has a singleton class. The singleton class is in a 1:1 relation with the object: the object has exactly one singleton class and each singleton class has exactly one instance, its object. So, when I said above that objects can have methods and those methods are called singleton methods? Well, that was a lie, too. Singleton methods are really just standard instance methods, which happen to be defined in the singleton class of an object, and thus can be called only on that object (because that object is the only instance of its singleton class).

So, when a method is defined in a singleton class, we call it a singleton method and when the singleton class belongs to a class, we call it a class method, but it's all just instance methods. (BTW: modules work the same way. In that case, they are called module methods or sometimes "module functions".)

The class pointer of an object always points to its singleton class. The actual class of an object is then the superclass of the singleton class, i.e. the singleton class's superclass pointer points to the actual class of the object. (Unless there are mixins, which become superclasses of the class they are mixed into, so if you mix a module into a singleton class, the module becomes the superclass of the singleton class, and the old superclass becomes the superclass of the module, or rather its include proxy class.)

What this means is that method lookup, which is the most often performed operation in an OO language, becomes really simple and really fast: grab the object, grab its class pointer, see if the method is there, grab the superclass pointer, see if the method is there, grab the superclass pointer … until you found the method.

It does mean that reflection gets a little more complex, but reflection is not a performance-critical operation. For example, if you ask an object for its class, you can't simply return the class pointer, as that would always be its singleton class and thus not very informative. You have to get the superclass, and the superclass's superclass and so on, until you end up at a class which is not a singleton class or an include proxy class.

But method lookup itself is very simple, and super always does what you expect.

In particular, when you create a new class, the singleton class of the superclass becomes the superclass of the singleton class of the subclass, so that "class methods" are inherited just as you would expect.

So, to recap: while Java has three different kinds of "methods" with different inheritance behavior (instance methods get inherited, static methods don't, constructors get inherited but have this super calling restriction), Ruby has only one. It has, however, three different kinds of classes: regular classes, singleton classes, and include proxy classes (created as proxies for mixins, when mixing a module into a class). The latter two are also called "virtual classes" inside of YARV, the most widely-used Ruby implementation.

One last thing: there are also so-called "global methods", sometimes called "global procedures" or "global functions". Again, as you probably guessed already, these don't exist. When you define a method outside of any class, it implicitly becomes a private instance method of Object and thus available for every object.

[I ignored two things here: BasicObject and prepend. These complicate matters somewhat, especially the latter. But the main mental model remains.]

Exact difference between overriding and hiding

Take a look at this answer to a different question by Eric Lippert.

To paraphrase (to the limits of my comprehension), these methods go into "slots". A has two slots: one for Test1 and one for Test2.

Since A.Test1 is marked as virtual and B.Test1 is marked as override, B's implementation of Test1 does not create its own slot but overwrites A's implementation. Whether you treat an instance of B as a B or cast it to an A, the same implementation is in that slot, so you always get the result of B.Test1.

By contrast, since B.Test2 is marked new, it creates its own new slot. (As it would if it wasn't marked new but was given a different name.) A's implementation of Test2 is still "there" in its own slot; it's been hidden rather than overwritten. If you treat an instance of B as a B, you get B.Test2; if you cast it to an A, you can't see the new slot, and A.Test2 gets called.

Overriding vs method hiding

Consider:

public class BaseClass
{
public void WriteNum()
{
Console.WriteLine(12);
}
public virtual void WriteStr()
{
Console.WriteLine("abc");
}
}

public class DerivedClass : BaseClass
{
public new void WriteNum()
{
Console.WriteLine(42);
}
public override void WriteStr()
{
Console.WriteLine("xyz");
}
}
/* ... */
BaseClass isReallyBase = new BaseClass();
BaseClass isReallyDerived = new DerivedClass();
DerivedClass isClearlyDerived = new DerivedClass();

isReallyBase.WriteNum(); // writes 12
isReallyBase.WriteStr(); // writes abc
isReallyDerived.WriteNum(); // writes 12
isReallyDerived.WriteStr(); // writes xyz
isClearlyDerived.WriteNum(); // writes 42
isClearlyDerived.writeStr(); // writes xyz

Overriding is the classic OO way in which a derived class can have more specific behaviour than a base class (in some languages you've no choice but to do so). When a virtual method is called on an object, then the most derived version of the method is called. Hence even though we are dealing with isReallyDerived as a BaseClass then functionality defined in DerivedClass is used.

Hiding means that we have a completely different method. When we call WriteNum() on isReallyDerived then there's no way of knowing that there is a different WriteNum() on DerivedClass so it isn't called. It can only be called when we are dealing with the object as a DerivedClass.

Most of the time hiding is bad. Generally, either you should have a method as virtual if its likely to be changed in a derived class, and override it in the derived class. There are however two things it is useful for:

  1. Forward compatibility. If DerivedClass had a DoStuff() method, and then later on BaseClass was changed to add a DoStuff() method, (remember that they may be written by different people and exist in different assemblies) then a ban on member hiding would have suddenly made DerivedClass buggy without it changing. Also, if the new DoStuff() on BaseClass was virtual, then automatically making that on DerivedClass an override of it could lead to the pre-existing method being called when it shouldn't. Hence it's good that hiding is the default (we use new to make it clear we definitely want to hide, but leaving it out hides and emits a warning on compilation).

  2. Poor-man's covariance. Consider a Clone() method on BaseClass that returns a new BaseClass that's a copy of that created. In the override on DerivedClass this will create a DerivedClass but return it as a BaseClass, which isn't as useful. What we could do is to have a virtual protected CreateClone() that is overridden. In BaseClass we have a Clone() that returns the result of this - and all is well - in DerivedClass we hide this with a new Clone() that returns a DerivedClass. Calling Clone() on BaseClass will always return a BaseClass reference, which will be a BaseClass value or a DerivedClass value as appropriate. Calling Clone() on DerivedClass will return a DerivedClass value, which is what we'd want in that context. There are other variants of this principle, however it should be noted that they are all pretty rare.

An important thing to note with the second case, is that we've used hiding precisely to remove surprises to the calling code, as the person using DerivedClass might reasonably expect its Clone() to return a DerivedClass. The results of any of the ways it could be called are kept consistent with each other. Most cases of hiding risk introducing surprises, which is why they are generally frowned upon. This one is justified precisely because it solves the very problem that hiding often introduces.

In all, hiding is sometimes necessary, infrequently useful, but generally bad, so be very wary of it.



Related Topics



Leave a reply



Submit