Consider the multilevel inheritance hierarchy in Java:
public class First {public String name() { return "First"; }}
public class Second extends First {
public void m1() {
System.out.print(super.name() + " rules");
System.out.prinln(" but " + name() + " is even better.");
}
public String name() { return "Second"; }}
public class Third extends Second {public String name() { return "Third"; }}
The Third class doesn't override the m1 method- it just inherits it. So if you run the following code:
Third varThird = new Third();
varThird.m1();
You get:
First rules but Third is even better.
This seems to violate the rule that at runtime, the actual type of the object is used to determine which implementation of the method is run. The method from the Second class appears to be the method that is run. How do you reconcile rules from Java inheritance (public methods are inherited by subclasses) with rules from polymorphism (at runtime, Java uses an object's actual type to determine which version of the method is implemented). Do methods that are not overridden in the subclass actually get "inherited"?
Ok, I think I undenstand the question now. You are confused about why super is rot resolved at runtime.
The reason is simple. Java only use the exact type to determine which method to call, for virtual methods. But constructors are not virtual, so a call to a constructor is always determined at compile time.
The search starts at the subtype for the method. Then the JVM successively goes further up the inheritance hierarchy to find the specific method.
It is called dynamic binding if I remember correctly.
Edit
Okay you are wondering why you get Third is even better. when m1() is only defined in Second. You are expecting the output Second is even better.
The method is inherited vom Subtyp Second as the JVM uses this method in the inheritance hierarchy as Third does not override this method.
In second you refer to
super().name where super() refers to the parent which in this case is First and therefore you get First rules but
Then you are invoking name() method which is defined in Third and therefore returning the name defined in Third
Related
This question already has answers here:
Why is it that we cannot override static and final methods? [duplicate]
(5 answers)
Closed 1 year ago.
In Java, what is the actual reason behind the inability to write a method in a sub class which has the same name as a final method in the super class? (Please note that I am not trying to override the method, this is why I have put the keyword final.)
Please see the example below:
class A {
public final void method() {
System.out.println("in method A");
}
}
class B extends A {
public void method() {
System.out.println("in method B");
}
}
The problem is expressed as "'method()' cannot override 'method()' in 'A'; overridden method is final" in the IDE; however, I would like to understand what it is about this situation that leads the compiler to fail.
Because in java, overriding isn't optional.
Names of methods at the class level.
At the class level (as in, what is in a class file, and what a JVM executes), method names include their return type and their parameter types (and, of course, the name). At the JVM level, varargs doesn't exist (it's an array instead), generics do not exist (they are erased for the purposes of signature), and the throws clause isn't a part of the story. But other than that, this method:
public void foo(String foo, int bar, boolean[] baz, long... args) throws Exception {}
turns into this name at the class file level:
foo(Ljava/lang/String;I[Z[J)V
which seems like gobbledygook, but [ is 'array of', the primitives get one letter each (Z for boolean, J for longs, I for integer), V is for void, and L is for: Object type. Now it makes sense.
That really is the method name at the class level, effectively (well, we call this its signature). ANY invocation of a method in java, at the class level, always uses the complete signature. This means javac simply cannot compile a method call unless it actually knows the exact method you're invoking, which is why javac doesn't work unless you have the full classpath of everything you're calling available as you compile.
Overriding isn't optional!
At the class level, if you define a method whose full signature matches, exactly, a signature in your parent class, then it is overriding that method. Period. You can't not. #Override as an annotation doesn't affect this in the slightest (That annotation merely causes the compiler to complain if you aren't overriding anything, it's compiler-checked documentation, that's all it is).
javac goes even further
As a language thing, javac will make bridges if you want to tighten the return type. Given:
class Parent {
Object foo() { return null; }
}
class Child extends Parent {
String foo() { return null; }
}
Then at the class level, the full signature of the one method in Parent is foo()Ljava/lang/Object; whereas the one in Child has foo()Ljava/lang/String; and thus these aren't the same method and Child's foo would appear not to be overriding Parent's foo.
But javac intervenes, and DOES make these override. It does this by actually making 2 methods in Child. You can see this in action! Write the above, compile it, and run javap -c -v on Child and you see these. javac makes 2 methods: Both foo()Ljava/lang/String; and foo()Ljava/lang/Object; (which does have the same signature and thus overrides, by definition, Parent's implementation). That second one is implemented as just calling the 'real' foo (the one returning string), and gets the synthetic flag.
Final is what it is
Which finally gets to your problem: Given that final says: I cannot be overridden, then, that's it. You've made 2 mutually exclusive rules now:
Parent's foo cannot be overriden
Child's foo, by definition (because its signatures match), overrides Parent's foo
Javac will just end it there, toss an error in your face, and call it a day. If you imagined some hypothetical javac update where this combination of factors ought to result in javac making a separate method: But, how? At the class level, same signature == same method (it's an override), so what do you propose? That java add a 0 to the end of the name?
If that's the plan, how should javac deal with this:
Parent p = new Child();
p.foo();
Which foo is intended there? foo()Ljava/lang/Object; from Parent, or foo0()L/java/Object; from child?
You can write a spec that gives an answer to this question (presumably, here it's obvious: Parent's foo; had you written Child c = new Child(); c.foo(); then foo0 was intended, but that makes the language quite complicated, and for what purpose?
The java language designers did not think this is a useful exercise and therefore didn't add this complication to the language. I'm pretty sure that was clearly the right call, but your opinion may of course be different.
Final means not just that you can’t override it, it means you can’t work around having that method get called.
When you subclass the object, if you could make a method that shadows that final method, then you could prevent the superclass method from functioning, or substitute some other functionality than what the user of the object would expect. This would allow introducing malicious code and would defeat the purpose of making methods final.
In your case it sounds like making the superclass method final may not have been the best choice.
public class Super {
public void methodA() {
System.out.println("super A");
}
public void methodC(Super arg) {
System.out.println("C1");
}
public void methodC(Sub arg) {
System.out.println("C2");
}
} // end class Super
public class Sub extends Super {
public void methodA() {
System.out.println("sub A");
}
public void methodC(Super arg) {
System.out.println("C3");
}
public void methodC(Sub arg) {
System.out.println("C4");
}
} // end class Sub
public class BindingQuestion {
public static void main (String[] args){
Super one = new Super();
Super two = new Sub();
Sub three = new Sub();
two.methodC(three)
}
}
I'm confused as to why two.method(C) returns C4. Isn't two declared as type Super. Shouldn't this mean that it accesses only the Super methods? I thought it would return C2. At least this is what I infered from an answer given to me by #stvcisco in a similar previous question. Dynamic Binding Java. Does an object have the methods of its declared type, or its actual type?
Am I misinterpreting his answer?
The instance method being called depends on the runtime type of the instance.
In Super two = new Sub();, the run time type is Sub (even though the compile time type is Super). Therefore two.methodC(three) calls Sub's methodC(Sub arg).
The compile time type determines the available method signatures that the compiler would accept. Since Super contains a method whose signature matches the call two.methodC(three), this code can pass compilation. However, the actual method that gets invoked is only determines at run time, based on the run time type of two.
Isn't two declared as type Super.
Yes it is.
Shouldn't this mean that it accesses only the Super methods?
No it does not mean this.
What happens is as follows:
At compilation time, the compiler checks if there is a method in Super which can handle methocC(Sub). There are actually two of them. methodC(Super) and methodC(Sub). The compiler selects the most specific signature to be bound at runtime. This one is the methodC(Sub), because Sub is a subclass of Super.
At runtime, the VM looks up for methodC(Sub) in the most specific class possible. This one is Sub, since there is a method defined there with the signature methodC(Sub), therefore this one is bound.
This is because you overwrite the two functions methodC(Super),methodC(Sub).And Super two = new Sub(),this is called polymorphism.It means it would point to the local variable "new Sub()" and the functions in Class Sub though you name it Class Super.And all about this is completing automatically.If you hava a method methodC(Super),methodC(Sub) in Class Super ,yet methodB(Super),methodB(Sub) in Class Sub.The same operation 'Super two = new Sub();two.methodC(Three);will return "C2".In addition, the question you ask is quite common.You need to write more code to understand it.It would be better to write a project with more classes.LikeClass Super;Class Sub1 extends Super;Class Sub2;...,Of course,you can also useInterface`!
Case 1) 'two' is a type of Super class but it contain sub class object. So when you call some method which is defined in both super and sub class then it call the sub class method because sub class has override that method. If it does not found those method in sub class then it call to the super class method.
Case 2) When you remove both of the method ' methodC(Sub arg)' from super and sub class then it call the sub class method 'methodC(Super arg)', if it does not found then it call super class method.
When a sub class object is assigned to super class object then it will
call first sub class method because sub class override super class
method.
What I think is most important while understanding the concept of Dynamic and Static Binding is that many times we think both types of bindings cannot take place within the scope of a program - that both these two are mutually exclusive This is not true. Its just that the two happen at different stages of the program execution and throw an error that time if any ambiguity is found. For example, in your case:
public class BindingQuestion {
public static void main (String[] args){
Super one = new Super();
Super two = new Sub();
Sub three = new Sub();
two.methodC(three)
}
}
During compile time ----------------
When the program is being compiled, the java compiler will traverse through each and every executable code. When it comes to
two.methodC(three)
it will first check if methodC(three) with this signature is available in the class of the type SUPER. Why Super? Because objects in java are accessed through reference. When you do this:
Super two = new Sub();
This means, for the reference two of type Super, you are pointing to an object of SUB. Which is fine. Why? Because in java, a subclasses always have a few extra properties besides the ones implanted into it by its superclass. So from the piece of code above all the properties of SUB which are common with two will work just fine - they will be easily accessed by the reference variable of SUPER type.
So, the compiler checks if the method
After the compiler has executed through the program and not found any ambiguity in terms of the type of the reference matching with the methodC(three) is present in the SUPER class or not.
According to the structure of inheritance that you have provided, is there a method called methodC is the SUPER class. Answer is yes! It does exists. Now, do the arguments match? In other words does the signature match? The answer is yes. Because in SUPER the signature expected in public void methodC(Sub arg). And guess what? Three, is of type SUB. So compiler will pass this line without creating any errors.
Coming to Run time
You must remember that Objects and invoked only and only at runtime. Check of types of methods and signatures is done during compile time.
Now, Java Runtime instance, while invoking the object two, realizes that actually the object two is of SUB class and invokes the method in the SUB class.
Hope this helped.
Below is the java class having 3 overloaded constructors :
public class Test {
public Test(Object i){
System.out.println("Object invoked");
}
public Test(String i){
System.out.println("String invoked");
}
public Test(int k){
System.out.println("Integer invoked");
}
public static void main(String[] args) throws Exception {
Test t = new Test(null);
}
}
If null value is passed while creating the new instance of class, which constructor will be invoked ? What is the reason ?
Java always chooses the most specific method (or constructor) that would be applicable for the argument you pass. In this case, that's the String constructor -- String is a subclass of Object.
Think about what would happen if you had
new Test("some string")
Both the Object and String constructors would be applicable here. After all, the argument is both an Object and a String. However, it is clear that the String constructor will be invoked because it is more specific than the Object constructor and still is applicable given the argument.
null is no different; these two constructors are still applicable, and the String constructor is still chosen over the Object one for the same reason.
Now, if there were two equally "specific" constructors present (e.g. if you had an Integer constructor) there would be a compilation error when you call Test(null).
This is outlined in more detail in JLS §15.12.2:
The second step searches the type determined in the previous step for member methods. This step uses the name of the method and the types of the argument expressions to locate methods that are both accessible and applicable, that is, declarations that can be correctly invoked on the given arguments.
There may be more than one such method, in which case the most specific one is chosen. The descriptor (signature plus return type) of the most specific method is one used at run time to perform the method dispatch.
The explicit process of determining which method is the most specific is outlined in JLS §15.12.2.5.
The answer is: Test(String) is invoked.
Why?
When determining which of a set of overloaded methods will be invoked, the Java compiler will attempt to match the most concrete type. And it will first attempt to match a signature before employing autoboxing. (#arshajii provided a perfect reference into the Java Language Spec on this)
Here, Object is the most abstract class in the type system. String subclasses from Object and is therefore more specific/concrete.
The logic behind this is that if you are overloading a method with a more specific-typed parameter, you're likely wanting to do more with that object (when you subclass, you typically add methods). If method signature determination worked the other way (i.e. the more abstractly-typed signature winning; here, Test(Object)), then none of the more concrete signatures would ever get called.
Take the following code:
public class Parent
{
public String doIt(Object o) {
return "parent";
}
}
public class Child extends Parent
{
public String doIt(Object s) {
return super.doIt(s) + ": " + "child";
}
}
public class Poly
{
public String makeItHappen() {
Parent p = new Child();
return p.doIt("test");
}
}
Due to the fact that Child.doIt() overrides Parent.doIt(), invoking Poly.makeItHappen() results in this being printed to the console:
parent: child
However, if I make a change in Child.doIt() to look like this:
public String doIt(String s) {
return super.doIt(s) + ": " + "child";
}
Now Child.doIt() does not override Parent.doIt(). When you invoke Poly.makeItHappen(), you get this result:
parent
I'm a bit puzzled by this. The compile-time type of p is Parent so I certainly understand it finding Parent.doIt() as a potentially applicable method, but, given that the run-time type of p is Child, I'm not certain why Child.doIt() is not. Presuming that they are both identified as potentially applicable methods, I would expect Child.doIt(String) to be invoked over Parent.doIt(Object) as it is more specific.
I've tried consulting the JLS and found this bit:
15.12.1 Compile-Time Step 1: Determine Class or Interface to Search
...
In all other cases, the qualified name has the form FieldName . Identifier; then the name of the method is the Identifier and the class or interface to search is the declared type T of the field named by the FieldName, if T is a class or interface type, or the upper bound of T if T is a type variable.
To me, that says that the compile-time type of p would be used. This makes some sense when I see Parent.doIt(Object) being invoked while Child.doIt(String) is not. But it doesn't make sense in the terms of the polymorphic behavior noted when Child.doIt() properly overrides Parent.doIt() - in that case, both methods of Parent and Child are being analyzed to find potentially applicable methods so why not in the second case, as well?
I know I'm missing something here, but I just can't figure out why I'm seeing the behavior that I am. If anyone could shed some insight into this, I'd appreciate it.
EDIT: FOUND THE ANSWER:
Thanks to Jack's response, I was able to find the answer within the JLS. The section of the JLS I referred to earlier was actually focused on finding the correct method at compile time and did not cover the process of invoking the correct method at run time. That portion of the process can be found the section of the JLS titled 15.12.4 Runtime Evaluation of Method Invocation.
In there, I found this bit of text:
Otherwise, the invocation mode is interface, virtual, or super, and overriding may occur. A dynamic method lookup is used. The dynamic lookup process starts from a class S, determined as follows:
My invocation mode is virtual, so the above statement applies...
If the invocation mode is interface or virtual, then S is initially the actual run-time class R of the target object.
...
The dynamic method lookup uses the following procedure to search class S, and then the superclasses of class S, as necessary, for method m.
Okay, so this seemed very odd to me. According to this, the JVM is going to start looking for an applicable method in Child to invoke, which would lead me to believe that Child.doIt(String) would be invoked. But, reading on...
Let X be the compile-time type of the target reference of the method invocation.
...
If class S contains a declaration for a non-abstract method named m with the same descriptor (same number of parameters, the same parameter types, and the same return type) required by the method invocation as determined at compile time (§15.12.3), then:
The class "S", which would be Child, does indeed contain a method with the same descriptor as the method invocation determined at compile time (String "is a" Object, after all, so the descriptors are identical). It still seems to be like Child.doIt(String) should be getting invoked, but reading on...
If the invocation mode is virtual, and the declaration in S overrides (§8.4.8.1) X.m, then the method declared in S is the method to be invoked, and the procedure terminates.
...
Otherwise, if S has a superclass, this same lookup procedure is performed recursively using the direct superclass of S in place of S; the method to be invoked is the result of the recursive invocation of this lookup procedure.
The bit in bold is the really important part of this. As I mentioned, when I changed the method Child.doIt(), it no longer was overriding the doIt() method from Parent. So, even though the JVM is evaluating the Child.doIt() method as a potential candidate for invocation, it fails to be invoked because it does not override the method defined in X, which is Parent. I was really getting hung up because I thought the JVM was not even check Child.doIt as a potentially applicable method, and that didn't seem correct. Now I believe that the JVM is checking that method as a potentially applicable method, but then disregards it because it doesn't properly override the parent method. It's a situation in which I thought that the method from the subclass would be invoked, not because it overrides the parent class method, but because it is the most specific. In this case, however, that isn't true.
The next line in the JLS simply explains that this procedure executes recursively over superclasses, leading Parent.doIt(Object) to be invoked.
Intuitively, this made complete sense to me but I just couldn't wrap my head around how the JVM was actually executing this process. Of course, looking in the correct part of the JLS would have helped a great deal.
Dynamic binding of the method applies at runtime between different implementations with the same signature but the set of all possible methods is determined statically when the compilers look at the signature. Since you declare p as a Parent class, at runtime it will look for a method that is present in the Parent class and, if a more specific implementation is present (because of a subclass, like in your example), then it will be chosen instead that the ancestor one.
Since your method does not override anything, at compile time it will choose a different signature (the one with Object) and ignore it. It doesn't appear as a matching possibility at runtime because of the type of attribute p.
Your answer is actually pretty simple: your change to the method broke your use of inheritance.
The Parent only has one doIt method, and it take an Object parameter. When you call doIt("test") on the parent, it looks to see if it is overridden in the child. Since doIt(Object s) is not overridden in the child, the parent method is utilized. Even though, you pass a String, the parent method will still be called since doIt(Object s) is not the same as doIt(String s).
Simply put, you are not overriding the method when you change the signature, you are overloading it.
The method signature to be invoked is determined at compile time, so p.doIt("test") will invoke the doIt(Object o) method of the appropriate class at runtime. doIt(String s) isn't even looked at. Imagine that Child.java didn't exist at the time that the Poly makeItHappen was written--you would also have to abstract the Child constructor away into a factory method in a different class to get it to compile. You could re-implement the factory method and Child.java without ever recompiling Poly.java. This allows you to program to the interface provided by the base class and relatively efficient function invocation. Your Poly makeItHappen only needs to know that a doIt(Object o) exists.
If you think of the possible implementation of inheritance as through a virtual function table, then doIt(String s) and doIt(Object o) have different table entries. Parent only has an entry for doIt(Object o). Child has both an entry for doIt(Object o) that is the same body as Parent and an entry for doIt(String s) that is its own. At compile time, the method to be invoked is the one in the doIt(Object o) slot.
You upcasted the Child to Parent
Parent p = new Child();
When you invoke p.doIt("test"); the only way you're going to get Child behavior is via an overridden method.
Since you changed the method in Child to doIt(String s), it is no longer overriding anything in Parent and so doIt(Object o) is called in the Parent.
Hmm, trying to address the 'why' the runtime doesn't play hide and go seek with the entire class definition looking for 'better' matches to a method than the one the compiler asked for, will go for an example. Obviously this API is horrible in the first place, but you can imagine how the situation could happen accidentally with very long method signatures.
/**
* Vendor API you program to
*/
public class IPv4Manager {
public void terminateSocket(Object obj) {
//terminate IPv4 socket
}
}
/**
* Vendor class that's injected at runtime that you have no knowledge of
* and do not compile against.
*/
public class IPv4And6Manager extends IPv4Manager {
public void terminateSocket(Byte[] packet) {
//terminate IPv6 socket
}
}
/**
*Your user code
*/
public void terminateIPv4Socket(Byte[] packet) {
IPv4Manager manager = managerFactory.getV4Manager(); //returns you an instance of 4And6Manager
manager.terminateSocket(packet);
}
Do you really want the runtime to try to outsmart you and call a "better" method than the one the compiler asked for?
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.