How is method overriding implemented in Java? In C++ we have the concept of vtable.. how is this implemented internally in Java?
To answer the question, which is specifically how overriding is implemented in the virtual machine, there's a write up available in Programming for the Java Virtual Machine (Google Books link).
The VM will look for an appropriate method definition in the referenced class, and then work its way up through the inheritance stack. Obviously at some stage various optimisations will apply.
See here for a description of the relevant bytecode instruction invokevirtual:
invokevirtual looks at the descriptor
given in , and determines
how many arguments the method takes
(this may be zero). It pops these
arguments off the operand stack. Next
it pops objectref off the stack.
objectref is a reference to the object
whose method is being called.
invokevirtual retrieves the Java class
for objectref, and searches the list
of methods defined by that class and
then its superclasses, looking for a
method called methodname, whose
descriptor is descriptor.
As gustafc has highlighted below, various optimisations can apply, and no doubt the JIT will introduce further.
Method overriding in Java is a concept based on polymorphism OOPS
concept which allows programmer to create two methods with same name
and method signature on interface and its various implementation and
actual method is called at runtime depending upon type of object at
runtime. Method overriding allows you to write flexible and extensible
code in Java because you can introduce new functionality with minimal
code change.
There are few rules which needs to be followed while overriding any method in Java, failure to follow these rules result in compile time error in Java.
First and most important rule regarding method overriding in Java is that you can only override method in sub class. You can not override method in same class.
Second important rule of method overriding in Java that name and signature of method must be same in Super class and Sub class or in interface and its implementation.
Third rule to override method in Java is that overriding method can not reduce accessibility of overridden method in Java. For example if overridden method is public than overriding method can not be protected, private or package-private; But opposite is true overriding method can increase accessibility of method in Java, i.e. if overridden method is protected than overriding method can be protected or public.
Another worth noting rule of method overriding in Java is that overriding method can not throw checked Exception which is higher in hierarchy than overridden method. Which means if overridden method throws IOException than overriding method can not throw java.lang.Exception in its throws clause because java.lang.Exception comes higher than IOException in Exception hierarchy. This rule doesn't apply to RuntimeException in Java, which is not even need to be declared in throws clause in Java.
You can not override private, static and final method in Java. private and static method are bonded during compile time using static binding in Java and doesn't resolve during runtime. overriding final method in Java is compile time error. Though private and static method can be hidden if you declare another method with same and signature in sub class.
Overridden method is called using dynamic binding in Java at runtime based upon type of Object.
If you are extending abstract class or implementing interface than you need to override all abstract method unless your class is not abstract. abstract method can only be used by using method overriding.
Always use #Override annotation while overriding method in Java. Though this is not rule but its one of the best Java coding practice to follow. From Java 6 you can use #Override annotation on method inherited from interface as well.
--Defining the same method with the same method signature(i.e. same number/type of arguments and same return type/s.)in base and derived class.
--Which method is to be called is decided at runtime so, it is also called runtime polymorphism/late binding.
--we should override the method defined in the superclass.
--when the method is called the method defined in the subclass is called and executed instead of the one in superclass.
--we overcome this by use of 'super' keyword.
//program
class A
{
void disp(){
System.out.println("class A");
}
}
class B extends A
{
public void disp(){
System.out.println("class B");
}
}
public class ExampleIdea{
public static void main(String[] args){
A a = new B(); //Parent reference but B class object (we can achieve polymorphism when parent class reference is used to refer a child class object)
B b = new B(); //B class reference and B class object
A c = new A();
a.disp(); //runs the method in B class
b.disp(); //runs the method in B class
c.disp(); //runs then method in A class
}
}//end of program
when we run this output will be class B.
In order to access the function of class A we have to use super keyword
as:
class B extends A
{
public void disp(){
System.out.println("class B");
super.disp();
}
Maybe this comparison of C++ Vtables and Java method invocation tables is of interest.
Method overriding
It means one method is available in supper class which is displaying some string, but you want to extend this class, and also you want to print your own method at that time you need to overriding this method into your local class.
This is a basic introduction to the method overriding.
Example:
class Animal
{
public void displayMessage()
{
System.out.println("Animal is eating");
}
}
class Dog extends Animal
{
public void displayMessage()
{
System.out.println("Dog is eating");
}
public static void main(String arg[])
{
Dog d=new Dog();
d.displayMessage();
}
}
OUTPUT:
Dog is eating
Advantages of Method Overriding is that the class ca give its own specific implementation to an inherited method without any modifying the parent class method.
The rules of Method overriding are:
The argument list : the argument list must be the same.
Access Modifier : if you're overriding the method you must give the same modifier of super class method suppose super class have the public method you cannot give the protected or private vice versa.
As long as the function (method) you wish to override is not marked as final you just simply override the method by extending the class which holds that method and then provide a method with same signature but different body.
Related
Maybe this question has obvious answer but i could not find it probably because im a java newbie.
Could you please say why in Java its possible to access class methods using signature of the interface from default method. I thought its possible to access methods only from class instance.
Example:
public interface test {
String voo();
default void foo() {
voo().toString();
}
}
As per JLS 9.4.3. Interface Method Body it's not prohibited to call another method inside the default interface method body:
A default method has a block body. This block of code provides an implementation of the method in the event that a class implements the interface but does not provide its own implementation of the method.
In practice default methods are not that different from class methods especially since Java 9 when one can have private interface methods:
public interface Test {
String voo();
default void foo() {
bar();
}
private void bar() {
voo().toString();
}
}
Default methods are instance methods. (JLS 9.4: Method declarations)
Instance methods are invoked on particular instances of objects. But a call to an instance method is made through a reference to an object of a type which declares that method. That type might be a superclass of, or an interface of, the actual object type at run time.
This allows us to write code that can operate on multiple types of objects through a common interface -- one kind of polymorphism.
Within an instance method, you can call other instance methods accessible through the type containing the calling instance method.
Optionally, you can do this through a keyword this, defined to be a reference to the object on which the instance method was called, of the type in which the keyword appears. The this keyword can be used in default methods. (JLS 15.8.3: this)
So, in your case, your default method could call either this.voo() or just voo().
public interface test {
String voo();
default void foo() {
this.voo().toString(); // Can call an instance method accessible through this type.
voo().toString(); // Equivalent call
}
}
Can anyone provide a simple example that explains the difference between Dynamic and Static polymorphism in Java?
Polymorphism
1. Static binding/Compile-Time binding/Early binding/Method overloading.(in same class)
2. Dynamic binding/Run-Time binding/Late binding/Method overriding.(in different classes)
overloading example:
class Calculation {
void sum(int a,int b){System.out.println(a+b);}
void sum(int a,int b,int c){System.out.println(a+b+c);}
public static void main(String args[]) {
Calculation obj=new Calculation();
obj.sum(10,10,10); // 30
obj.sum(20,20); //40
}
}
overriding example:
class Animal {
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move();//output: Animals can move
b.move();//output:Dogs can walk and run
}
}
Method overloading would be an example of static polymorphism
whereas overriding would be an example of dynamic polymorphism.
Because, in case of overloading, at compile time the compiler knows which method to link to the call. However, it is determined at runtime for dynamic polymorphism
Dynamic (run time) polymorphism is the polymorphism existed at run-time. Here, Java compiler does not understand which method is called at compilation time. Only JVM decides which method is called at run-time. Method overloading and method overriding using instance methods are the examples for dynamic polymorphism.
For example,
Consider an application that serializes and de-serializes different
types of documents.
We can have ‘Document’ as the base class and different document type
classes deriving from it. E.g. XMLDocument , WordDocument , etc.
Document class will define ‘ Serialize() ’ and ‘ De-serialize() ’
methods as virtual and each derived class will implement these
methods in its own way based on the actual contents of the documents.
When different types of documents need to be
serialized/de-serialized, the document objects will be referred by
the ‘ Document’ class reference (or pointer) and when the ‘
Serialize() ’ or ‘ De-serialize() ’ method are called on it,
appropriate versions of the virtual methods are called.
Static (compile time) polymorphism is the polymorphism exhibited at compile time. Here, Java compiler knows which method is called. Method overloading and method overriding using static methods; method overriding using private or final methods are examples for static polymorphism
For example,
An employee object may have two print() methods one taking no
arguments and one taking a prefix string to be displayed along with
the employee data.
Given these interfaces, when the print() method is called without any
arguments, the compiler, looking at the function arguments knows which function is meant to be called and it generates the object code
accordingly.
For more details please read "What is Polymorphism" (Google it).
Binding refers to the link between method call and method definition.
This picture clearly shows what is binding.
In this picture, “a1.methodOne()” call is binding to corresponding methodOne() definition and “a1.methodTwo()” call is binding to corresponding methodTwo() definition.
For every method call there should be proper method definition. This is a rule in java. If compiler does not see the proper method definition for every method call, it throws error.
Now, come to static binding and dynamic binding in java.
Static Binding In Java :
Static binding is a binding which happens during compilation. It is
also called early binding because binding happens before a program
actually runs
.
Static binding can be demonstrated like in the below picture.
In this picture, ‘a1’ is a reference variable of type Class A pointing to object of class A. ‘a2’ is also reference variable of type class A but pointing to object of Class B.
During compilation, while binding, compiler does not check the type of object to which a particular reference variable is pointing. It just checks the type of reference variable through which a method is called and checks whether there exist a method definition for it in that type.
For example, for “a1.method()” method call in the above picture, compiler checks whether there exist method definition for method() in Class A. Because ‘a1′ is Class A type. Similarly, for “a2.method()” method call, it checks whether there exist method definition for method() in Class A. Because ‘a2′ is also Class A type. It does not check to which object, ‘a1’ and ‘a2’ are pointing. This type of binding is called static binding.
Dynamic Binding In Java :
Dynamic binding is a binding which happens during run time. It is also
called late binding because binding happens when program actually is
running.
During run time actual objects are used for binding. For example, for “a1.method()” call in the above picture, method() of actual object to which ‘a1’ is pointing will be called. For “a2.method()” call, method() of actual object to which ‘a2’ is pointing will be called. This type of binding is called dynamic binding.
The dynamic binding of above example can be demonstrated like below.
Reference static-binding-and-dynamic-binding-in-java
method overloading is an example of compile time/static polymorphism because method binding between method call and method definition happens at compile time and it depends on the reference of the class (reference created at compile time and goes to stack).
method overriding is an example of run time/dynamic polymorphism because method binding between method call and method definition happens at run time and it depends on the object of the class (object created at runtime and goes to the heap).
In simple terms :
Static polymorphism : Same method name is overloaded with different type or number of parameters in same class (different signature). Targeted method call is resolved at compile time.
Dynamic polymorphism: Same method is overridden with same signature in different classes. Type of object on which method is being invoked is not known at compile time but will be decided at run time.
Generally overloading won't be considered as polymorphism.
From java tutorial page :
Subclasses of a class can define their own unique behaviors and yet share some of the same functionality of the parent class
Method Overloading is known as Static Polymorphism and also Known as Compile Time Polymorphism or Static Binding because overloaded method calls get resolved at compile time by the compiler on the basis of the argument list and the reference on which we are calling the method.
And Method Overriding is known as Dynamic Polymorphism or simple Polymorphism or Runtime Method Dispatch or Dynamic Binding because overridden method call get resolved at runtime.
In order to understand why this is so let's take an example of Mammal and Human class
class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
class Human extends Mammal {
#Override
public void speak() { System.out.println("Hello"); }
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
}
I have included output as well as bytecode of in below lines of code
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
And by looking at above code we can see that the bytecodes of humanMammal.speak() , human.speak() and human.speak("Hindi") are totally different because the compiler is able to differentiate between them based on the argument list and class reference. And this is why Method Overloading is known as Static Polymorphism.
But bytecode for anyMammal.speak() and humanMammal.speak() is same because according to compiler both methods are called on Mammal reference but the output for both method calls is different because at runtime JVM knows what object a reference is holding and JVM calls the method on the object and this is why Method Overriding is known as Dynamic Polymorphism.
So from above code and bytecode, it is clear that during compilation phase calling method is considered from the reference type. But at execution time method will be called from the object which the reference is holding.
If you want to know more about this you can read more on How Does JVM Handle Method Overloading and Overriding Internally.
Polymorphism:
Polymorphism is the ability of an object to take on many forms. The most common use of polymorphism in OOP occurs when a parent class reference is used to refer to a child class object.
Dynamic Binding/Runtime Polymorphism :
Run time Polymorphism also known as method overriding. In this Mechanism by which a call to an overridden function is resolved at a Run-Time.
public class DynamicBindingTest {
public static void main(String args[]) {
Vehicle vehicle = new Car(); //here Type is vehicle but object will be Car
vehicle.start(); //Car's start called because start() is overridden method
}
}
class Vehicle {
public void start() {
System.out.println("Inside start method of Vehicle");
}
}
class Car extends Vehicle {
#Override
public void start() {
System.out.println("Inside start method of Car");
}
}
Output:
Inside start method of Car
Static Binding /compile-time polymorphism:
Which method is to be called is decided at compile-time only.
public class StaticBindingTest {
public static void main(String args[]) {
Collection c = new HashSet();
StaticBindingTest et = new StaticBindingTest();
et.sort(c);
}
//overloaded method takes Collection argument
public Collection sort(Collection c){
System.out.println("Inside Collection sort method");
return c;
}
//another overloaded method which takes HashSet argument which is sub class
public Collection sort(HashSet hs){
System.out.println("Inside HashSet sort method");
return hs;
}
}
Output:
Inside Collection sort metho
Static Polymorphism: is where the decision to resolve which method to accomplish, is determined during the compile time. Method Overloading could be an example of this.
Dynamic Polymorphism: is where the decision to choose which method to execute, is set during the run-time. Method Overriding could be an example of this.
Polymorphism refers to the ability of an object to behave differently for the same trigger.
Static polymorphism (Compile-time Polymorphism)
Static Polymorphism decides which method to execute during compile
time.
Method Overloading is an example of static polymorphism, and it is
requred to happens static polymorphism.
Static Polymorphism achieved through static binding.
Static Polymorphism happens in the same class.
Object assignment is not required for static polymorphism.
Inheritance not involved for static polymorphism.
Dynamic Polymorphism (Runtime Polymorphism)
Dynamic Polymorphism decides which method to execute in runtime.
Method Overriding is an example of dynamic polymorphism, and it is
requred to happens dynamic polymorphism.
Dynamic Polymorphism achieved through dynamic binding.
Dynamic Polymorphism happens between different classes.
It is required where a subclass object is assigned to super class
object for dynamic polymorphism.
Inheritance involved for dynamic polymorphism.
Compile time polymorphism(Static Binding/Early Binding): In static polymorphism, if we call a method in our code then which definition of that method is to be called actually is resolved at compile time only.
(or)
At compile time, Java knows which method to invoke by checking the method signatures. So, this is called compile-time polymorphism or static binding.
Dynamic Polymorphism(Late Binding/ Runtime Polymorphism): At run time, Java waits until runtime to determine which object is actually being pointed to by the reference. Method resolution was taken at runtime, due to that we call as run time polymorphism.
Consider the code below:
public class X
{
public void methodA() // Base class method
{
System.out.println ("hello, I'm methodA of class X");
}
}
public class Y extends X
{
public void methodA() // Derived Class method
{
System.out.println ("hello, I'm methodA of class Y");
}
}
public class Z
{
public static void main (String args []) {
//this takes input from the user during runtime
System.out.println("Enter x or y");
Scanner scanner = new Scanner(System.in);
String value= scanner.nextLine();
X obj1 = null;
if(value.equals("x"))
obj1 = new X(); // Reference and object X
else if(value.equals("y"))
obj2 = new Y(); // X reference but Y object
else
System.out.println("Invalid param value");
obj1.methodA();
}
}
Now, looking at the code you can never tell which implementation of methodA() will be executed, Because it depends on what value the user gives during runtime. So, it is only decided during the runtime as to which method will be called. Hence, Runtime polymorphism.
Method overloading is a compile time polymorphism, let's take an example to understand the concept.
class Person //person.java file
{
public static void main ( String[] args )
{
Eat e = new Eat();
e.eat(noodle); //line 6
}
void eat (Noodles n) //Noodles is a object line 8
{
}
void eat ( Pizza p) //Pizza is a object
{
}
}
In this example, Person has a eat method which represents that he can either eat Pizza or Noodles. That the method eat is overloaded when we compile this Person.java the compiler resolves the method call " e.eat(noodles) [which is at line 6] with the method definition specified in line 8 that is it method which takes noodles as parameter and the entire process is done by Compiler so it is Compile time Polymorphism.
The process of replacement of the method call with method definition is called as binding, in this case, it is done by the compiler so it is called as early binding.
Following on from Naresh's answer, dynamic polymorphism is only 'dynamic' in Java because of the presence of the virtual machine and its ability to interpret the code at run time rather than the code running natively.
In C++ it must be resolved at compile time if it is being compiled to a native binary using gcc, obviously; however, the runtime jump and thunk in the virtual table is still referred to as a 'lookup' or 'dynamic'. If C inherits B, and you declare B* b = new C(); b->method1();, b will be resolved by the compiler to point to a B object inside C (for a simple class inherits a class situation, the B object inside C and C will start at the same memory address so nothing is required to be done; it will be pointing at the vptr that they both use). If C inherits B and A, the virtual function table of the A object inside C entry for method1 will have a thunk which will offset the pointer to the start of the encapsulating C object and then pass it to the real A::method1() in the text segment which C has overridden. For C* c = new C(); c->method1(), c will be pointing to the outer C object already and the pointer will be passed to C::method1() in the text segment. Refer to: http://www.programmersought.com/article/2572545946/
In java, for B b = new C(); b.method1();, the virtual machine is able to dynamically check the type of the object paired with b and can pass the correct pointer and call the correct method. The extra step of the virtual machine eliminates the need for virtual function tables or the type being resolved at compile time, even when it could be known at compile time. It's just a different way of doing it which makes sense when a virtual machine is involved and code is only compiled to bytecode.
Consider the following case,
interface IFace1 {
default void printHello() {
System.out.println("IFace1");
}
}
interface IFace2 {
void printHello();
}
public class Test implements IFace1, IFace2 {
public static void main(String[] args) {
Test test = new Test();
test.printHello();
IFace1 iface1 = new Test();
iface1.printHello();
IFace2 iface2 = new Test();
iface2.printHello();
}
#Override
public void printHello() {
System.out.println("Test");
}
}
In above example I am getting following output which is quite expected.
Test
Test
Test
I have been reading about Java-8 default methods and specifically about Extending Interfaces That Contain Default Methods
2nd bullet : Redeclare the default method, which makes it abstract.
In above example where I have two interfaces which have default method with same name and when I implemented both I was only able to reach to the implementation of printHello of Test which refers to IFace2.
I have few questions about this,
How can I reach to the printHello method of IFace1 and if I can't than why ?
Doesn't this behavior keep me away from the intended nature of IFace1 which is may be now shadowed by other method ?
Quote says, you can make the default method abstract in it's child interface. For example,
interface IFace2 extends IFace1 {
void printHello();
}
Here when I implement IFace2 I won't be actually able to reach default method of IFace1 that is exactly what is happening in my case.
It seems that you are a bit confused by the presence of a default method. So let’s forget for a moment that IFace1.printHello() is a default method. So then, there is a clear situation: Test implements two interfaces, IFace1 and IFace2, which happen to have a method with the same name and signature.
Test implements that method and therefore implements the method for both interfaces. The new feature of default methods does not change anything about this logic. Moreover, the language designers took care that adding a default method does not affect the behavior of existing code, so if your class implements the method, the presence of default methods becomes irrelevant.
However, if you write code that is aware of the presence of default methods, you may invoke it, if it is declared or inherited by a direct super interface, i.e. in your code you may use IFace1.super.printHello() to invoke the default method of IFace1.
The rules are not much different to the rules of super classes. If you change the interfaces so that interface IFace2 extends IFace1 and still declares printHello() as an abstract method, then this abstract method does override the default method and you can’t invoke IFace1.super.printHello() from within Test anymore.
As said, these rules are not much different to ordinary instance methods. If Test declares a method printHello(), that’s the only method that you can invoke by a reference to a Test instance, regardless whether its declared type is Test, IFace1 or IFace2. Only implementation methods of Test itself may do super invocations.
The main difference comes into play when the possible multiple inheritance of interfaces is involved. If your class Test does not implement the method printHello(), it depends on the inheritance relationship of the two interfaces, what will happen
If IFace2 extends IFace1, it’s abstract method redeclares the default method, hence a compiler error occurs, as Test must implement the abstract method
If IFace2 does not extend IFace1, there are ambiguously two inheritable methods with the same name and signature, therefore Test will not inherit the default method, and a compiler error occurs, as Test must implement the abstract method
If IFace1 extends IFace2, Test will inherit the default method. It will also inherit it if Test does not implement IFace2, but this should come at a surprise…
How can I reach to the printHello method of IFace1 and if I can't than why ?
You can only do so within an instance method of a type that implements IFace1 with
IFace1.super.printHello(); // only if IFace1 declares a default implementation of the method
In other words, you can't do it through a simple reference of type IFace1 or Test (or whatever). That would break encapsulation.
Doesn't this behavior keep me away from the intended nature of IFace1
which is may be now shadowed by other method ?
There's no shadowing going on here. You've overriden the method, so the overriden one gets invoked.
Concerning your 3rd question, you haven't extended any interfaces, so I don't see the relevance.
If you really did have
interface IFace2 extends IFace1 {
void printHello();
}
with
public class Test implements IFace2 {
then you would not be able to access IFace1's default implementation of the method. You can never skip super types to access implementations higher up in the inheritance hierarchy.
I would like to know how does JVM differentiates between method overloading and method overriding internally.
The JVM only deals with method overriding. A method is overridden by adding a method with the same signature in a derived class (the only allowed difference is in the return type, which is allowed to be more specific). The signature encodes the method's name, as well as the types of the parameters and the return type.
Method overloading means having multiple methods with the same "simple name" but different signatures. At compile time, the javac compiler chooses one of the same-named methods based on the types of the arguments and places its signature in the compiled .class file. A method invocation in compiled Java bytecode must specify the signature of the callee.
Jvm in not involved in method overloading. So it does not have to differentiate between method overloading and method overriding.
You would understand this clearly if you understand how method overloading and method overriding is implemented by Java behind the scenes.
Before going into the difference between overloading and overriding , let us first take a look into Polymorphism .
What is polymorphism ?
Polymorphism is the capability of a method to do different things based on the object that it is acting upon. In other words, polymorphism allows you define one interface and have multiple implementations.
Different types of polymorphism in java.
1) Method Overloading
2) Method Overriding
Types of polymorphism in java: Static, Dynamic, Runtime and Compile time
Now let us come back to the original question and understand the difference between overloading and overriding.
1. The first and most important is that method overloading a compile time polymorphism while method overriding is run time polymorphism. So JVM has to only deal with method overriding . Method overloading is already resolved after compilation.
2.In Method Overloading, methods must have different signature.In Method Overriding, methods must have same signature.
There are many more differences, but above two can really differentiate method overloading from method overriding.
Before winding up let us also look at what each is trying to achieve .
Method Overloading is to “add” or “extend” more to method’s behavior.Method Overriding is to “Change” existing behavior of method.
Method overloading is handled by the compiler (that's why known as static binding) while overriding is handled by JVM.
Overloaded methods are different and can be recognized separately based on the argument list, that's why they get resolved by the compiler at compile time.
Method overriding occurs when we try to call a overridden method on the parent reference which is holding child object. Because we are calling the method on parent reference so at compile time method get resolved from parent reference type so, for the compiler, the method of parent is getting called. But parent is holding the object of child so at runtime method gets called from child.
In order to understand how Java (Compiler + JVM) handles both things internally let's take an example of Mammal and Human class
public class OverridingInternalExample {
private static class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
private static class Human extends Mammal {
#Override
public void speak() { System.out.println("Hello"); }
// Valid overload of speak
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
#Override
public String toString() { return "Human Class"; }
}
// Code below contains the output and bytecode of the method calls
public static void main(String[] args) {
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
}
}
When we compile above code and try to look at the bytecode using javap -verbose OverridingInternalExample, we can see that compiler generate a constant table where it assigns integer codes to every method call.
I have included the bytecode along with above method calls and by looking at above code we can see that the bytecodes of humanMammal.speak() , human.speak() and human.speak("Hindi") are totally different because the compiler is able to differentiate between them based on the argument list and class reference. And this is why Method Overloading is known as Static Polymorphism or Static Binding.
But bytecode for anyMammal.speak() and humanMammal.speak() is same because according to compiler both methods are called on Mammal reference but the output for both method calls is different because at runtime JVM knows what object the reference is holding and JVM calls the method on the object and this is why Method Overriding is known as Dynamic Polymorphism or simply Polymorphism.
If you want to know more about this you can read more on How Does JVM Handle Method Overloading and Overriding Internally.
Though name of method remains same in case of both method overloading and overriding, main difference comes form the fact that method overloading is resolved during compile time, while method overriding is resolved at runtime. Also rules of overriding or overloading a method is different in Java. For example, private, static and final method cannot be overriding in Java but you can still overload them. For overriding both name and signature of method must remain same, but in for overloading method signature must be different. Last but not the least difference between them is that call to overloaded methods are resolved using static binding while call to overridden method is resolved using dynamic binding in Java. SO JVM is not involved in overloading
Method overloading:
class Calculation{
void sum(int a,int b){System.out.println(a+b);}
void sum(int a,int b,int c){System.out.println(a+b+c);}
}
Method Overriding:
class Calculation{
void sum(){System.out.println("sum in superclass");}
}
class Specific extends Calculation{
void sum(){System.out.println("sum in Specific");}
}
I know that a child cannot reduce the visibility of a non-static method and I understand why it is so.
I've read however that "static method can be hidden through its redeclaration". I however do not understand how this could be achieved in Java.
Is this really possible? If yes, how to do that (code example) and why was it introduced (it seems to contradict the principle of non-reducing the visibility of the interface)?
The short answer is: no, it is not possible. You have mixed up some terminology. Hiding has nothing to do with accessibility (which is what you are really asking about, not visibility, which is related to scope and shadowing and is discussed in Chapter 6 of the Java Language Specification (JLS)).
Now for the longer answer. The term overriding applies to instance methods, while the term hiding applies to class (static) methods. From the Java Tutorial topic Overriding and Hiding Methods:
The distinction between hiding a static method and overriding an instance method has important implications:
The version of the overridden instance method that gets invoked is the one in the subclass.
The version of the hidden static method that gets invoked depends on whether it is invoked from the superclass or the subclass.
Some of the other answers here provide incorrect examples about method hiding, so let's go back to the JLS, this time to §8.4.8:
Methods are overridden or hidden on a signature-by-signature basis.
That is, to override or hide a method in the parent class, the subclass must define a method with the same signature—basically, the same number and type of arguments (although generics and type erasure makes the rules a little more complicated than that). There are also rules about return types and throws clauses, but those seem irrelevant to this question.
Note that you can define a method in a subclass with the same name as a method in the parent class (or in an implemented interface) but with different number or type of arguments. In that case, you are overloading the method name and neither overriding nor hiding anything; the subclass method is a new method, pretty much independent of the inherited method(s). (There is an interaction when the compiler has to match methods to method calls, but that's about it.)
Now to your question: the terms accessibility and hiding (as well as visibility) are independent concepts in Java. There is, as you put it, a "principle" that there is simply no way for a subclass to reduce the accessibility of an inherited method. This applies regardless of whether you are overriding an instance method or hiding a class method. From the JLS §8.4.8.3:
The access modifier (§6.6) of an overriding or hiding method must provide at least as much access as the overridden or hidden method, as follows:
If the overridden or hidden method is public, then the overriding or hiding method must be public; otherwise, a compile-time error occurs.
If the overridden or hidden method is protected, then the overriding or hiding method must be protected or public; otherwise, a compile-time error occurs.
If the overridden or hidden method has default (package) access, then the overriding or hiding method must not be private; otherwise, a compile-time error occurs.
In summary, the fact that a static method can be hidden has nothing to do with changing the accessibility of the method.
Based on hagubear's valuable comments, it seems that the author of a statement meant hiding a method through overloading it with a method having the same declaration.
Quoting this link:
We can declare static methods with same signature in subclass, but it
is not considered overriding as there won’t be any run-time
polymorphism. (...) If a derived class defines a
static method with same signature as a static method in base class,
the method in the derived class hides the method in the base class.
Thus, defining a method in a child class having exact same declaration effectively hides the original method in child. However, as in case of fields, casting to the parent will restore the original access.
Sample code:
public class Test {
public static void main( String[] args ) {
B b = new B();
A a = b;
b.f(); // "Access somewhat denied"
a.f(); // "f()"
}
}
class A {
public static void f() {
System.out.println("f()");
}
}
class B extends A {
// *must* be public
public static void f() {
System.out.println("Access somewhat denied");
}
}
So I created a trivial test; IntelliJ indeed rejected it... and Yes, I know "it's a tool...but one I trust". In any case, I went to javac, which emitted the same ERROR:
Error:(...) java: ...Concrete.java:5: doSomethingStatic() in
...Concrete cannot override doSomethingStatic() in
...Base; attempting to assign weaker access privileges; was public
Based on this, and our skepticism in general, I suggest the error is in your documentation.
Below is my sample code, fairly definitive I think. It barfs at the protected.
public class Base
{
public static void doSomethingStatic(){}
}
public class Concrete extends Base
{
protected static void doSomethingStatic(){}
}
It can be hidden by an overloaded redeclaration in a derived class:
class Base
{
public static void doSomethingStatic(){}
}
class Derived extends Base
{
public static void doSomethingStatic(String arg){}
}
but only hidden to people who try to access it via the derived class.