My included code's output is pretty ugly, but it's just a code for understanding how different things may work in Java. The questioned line is marked with comments on the bottom half of the code.
class CsTorta extends Torta{
public CsTorta retegez(CsTorta a){
....
}
public CsTorta retegez(Torta a){
System.out.println("This method"); //<-----it calls this one and not the one above
....
}
}
public class NewClass {
public static void main(String[] args) {
Torta tt=new Torta(5);
Torta tcs=new CsTorta(3);
CsTorta cs=new CsTorta(4);
System.out.println("");
System.out.println(tcs.retegez(tcs)); //The line in question uses the cstorta retegez method (marked with "This method")
}
}
While the tcs's type in coding-time is the reference type, in runtime when i call the tcs.retegez method it recognizes its a cstorta type, but the parameter which is the same tcs remains the reference type (thats why it uses the cstorta marked method).
My question is: Is my conclusion correct: that the program only checks the "real" type of the object if it calls a method, and uses the reference type if it does not?
That's pretty much correct. What is needed here is understanding the difference between overloading and overriding.
Overriding occurs when you have a class that declares an instance method, and a subclass that declares the same method (same name, same parameters--the result type is usually the same but could be a subclass). There are multiple methods to choose from, but the exact method is determined at run time.
public class A {
public void method1(String s1, int s2) { ... }
}
public class B extends A {
#Override
public void method1(String s1, int s2) { ... }
}
A object = new B();
object.method1("xxx",2);
The decision about which method1 is run isn't made until run time. object's real type is B, so the method1 declared in B is called.
Overloading is when two methods with the same name, but different parameters, are both present. By different parameters, I mean that the number of parameters is different, or the number of parameters is the same but the types are different. That is, they have different signatures. In that case, the decision on which method to call is made at compile time. (You can have a case where both overriding and overloading occur. The decision about which parameter signature to choose is made at compile time; but if there are multiple overriding methods with the same signature, the choice between those methods is made at run time.)
The key thing to remember is that if the decision is made at compile time, the compiler will not know what the "real" type of the object is. All it knows is how you've declared it. Thus:
public CsTorta retegez(CsTorta a){ // Number 1
....
}
public CsTorta retegez(Torta a){ // Number 2
System.out.println("This method"); //<-----it calls this one and not the one above
....
}
These are overloaded methods.
Your code looks like:
Torta tcs = // the compiler doesn't care
System.out.println(tcs.retegez(tcs));
The compiler has to decide whether to call Number 1 or Number 2. All the compiler knows is that the parameter is a Torta. The actual value could be an object of Torta, CsTorta, or any other class. Or it could be null (all right, you can't call tcs.retegez if it's null, but if you said tcs.retegez(tcs2), then tcs2 could be null.) The compiler doesn't know, and doesn't care. All it knows is that it was declared as a Torta, so it chooses the overloaded method with the Torta parameter.
(To clarify further: the compiler will choose the deepest subclass it can. Example:)
class AnotherTorta extends Torta { ... }
class YetAnotherTorta extends CsTorta { ... }
AnotherTorta t3 = // whatever
YetAnotherTorta t4 = // whatever
tcs.retegez(t3);
// since AnotherTorta can't be cast to CsTorta, it chooses the Torta parameter
tcs.retegez(t4);
// here, t4 can be cast to either a Torta or CsTorta parameter, so it chooses the subclass, CsTorta
Related
In the following program, I have one single method in class A overloaded 3 times and then in subclass B, all 3 overloaded methods are overridden.
obj3 is an object with reference type A(superclass) and object type B(subclass) and it calls the method from B on execution, which is expected behavior.
Since overloading and overriding both exist in this code, does that mean that it performed static binding at compile time (to the matching method in class A) and then dynamic binding at run time (to method in class B). Can they both occur together?
My assumption is that this is a classic case of dynamic binding as I believed "binding" is meant to be a permanent action, but a peer suggests that it is both together(static first, then dynamic).
class A{
public void method(Integer n){
System.out.println("Integer: "+n);
}
public void method(String s){
System.out.println("String: "+s);
}
public void method(String s, Integer n){
System.out.println("String: "+s+" Integer: "+n);
}
}
class B extends A{
public void method(Integer n){
System.out.println("Integer(from B): "+n);
}
public void method(String s){
System.out.println("String(from B): "+s);
}
public void method(String s, Integer n){
System.out.println("String(from B): "+s+" Integer(from B): "+n);
}
}
public class Test{
public static void main(String[] args){
A obj1 = new A();
B obj2 = new B();
A obj3 = new B();
System.out.println("Integer form of method");
// Integer form of method
System.out.println("Ref A Obj A");
// Ref A Obj A
obj1.method(1);
// Integer: 1
System.out.println("Ref B Obj B");
// Ref B Obj B
obj2.method(2);
// Integer(from B): 2
System.out.println("Ref A Obj B");
// Ref A Obj B
obj3.method(3);
// Integer(from B): 3
}
}
Since overloading and overriding both exist in this code, does that mean that it performed static binding at compile time (to the matching method in class A) and then dynamic binding at run time (to method in class B)
Right. The compiler chose the matching signature, and this is static, based on the type of the variable (A in this case).
At runtime, Java finds the implementation of the signature selected by the compiler. This is dynamic, based on the runtime class of obj3 (B, in this case).
You right. Compiler is statically choose between overloads in class A and put that information into .class file in form of method FQN.
Then runtime dynamically choose between implementation of that method.
One more attempt to make it clear:
Overloading
Overloading means that a single class has multiple methods with different parameter types (aka. signatures), and you just happened to give them the same name. Your program will work the very same if you change to individual names for the methods, e.g. methodI(Integer n), methodS(String s), and methodSI(String s, Integer n).
Or, you can imagine the compiler to internally always append such a types list to the method name.
Overloading is resolved by the compiler, based on the compile-time types of the parameter expressions.
E.g. if you write
Object par = "Test";
a.method(par);
you get a compiler error. Even though we all see it's a String that you are passing into the method, the compiler only sees an Object, and finds no matching method. Only if you were to introduce an additional method(Object o), the compiler would choose that one. And runtime would call that method and not the String version!
Overriding
Overriding means that at runtime the JVM calls the method implementation depending on the runtime class of the "object before the dot".
And in this case, "method" is to be read as the overloaded method version that the compiler found to match the parameter list. So, runtime already knows whether methodI(), methodS(), or methodSI() is meant, and only decides from which class to take the implementation.
Personal opinion
Allowing multiple methods to share the same name, but differ in parameter lists (aka overloading), produces too much confusion for its benefit.
Studying "cracking the coding interview" in Java, on page 51 I came across:
void permutation(String str){
permutation(str,"");
}
void permutation(String str, String prefix){
if(str.length()==0){
System.out.println(prefix);
} else{
for(int i=0;i<str.length();i++){
String rem=str.substring(0,i)+str.substring(i+1);
permutation(rem,prefix+str.charAt(i));
}
}
}
I get that the first permutation function takes a string and calls the second permutation function which does all the work. However, isn't the second permutation a redeclaration of the first permutation function? How will Java recognize and use the first permutation function and not overwrite it?
How will java recognize and use the first permutation function?
When you call the method, Java will see what you're trying pass into it. Based on the arguments you pass, it will decide which 'version' of the method you are trying to use.
Like others have said - this is method overloading
Unlike in Python, in Java these two declarations live side-by-side -- the second doesn't replace the first. In Java, the rule is roughly that when you call a method with multiple definitions (aka an "overloaded" method), Java will look for the one that best matches the arguments you called it with and run that method. So permutation("hi") invokes the first version, and permutation("hi", "") calls the second.
The fundamental difference here is that in Python you can imagine the interpreter reading the definitions one at a time and replacing its overall definition of permutation every time it gets a new definition. In Java, you have to think of it as reading all the definitions of permutation at once, and calling the most appropriate one for any given invocation.
(A consequence of this is that Java also checks at compile-time that every overloaded version of a method is callable: for instance, if you wrote two versions of permutation that both took just a string as their argument, the compiler would give you an error and wouldn't compile your program at all. In python you'd just get the second definition.)
To explain what the semantics are, we need to take a look at how Java methods are differentiated.
In Java, a method is identified by its signature. JLS ยง8.4.2 specifies that
Two methods have the same signature if they have the same name and argument types.
Important to note is that the return type of a method is not part of a method's signature. Thus if one would write:
public class Foo {
void bar(String baz) {
}
String bar(String baz) {
}
}
Both methods would have the same signature. In Java, this would lead to a compilation error since it is not allowed to have two methods with the same signature in the same class.
The behaviour changes if we take inheritance into the picture:
public class Foo {
void bar(String baz);
}
public class Zoo extends Foo {
#Override
void bar(String baz);
}
In this case, class Zoo overrides method bar(...) of class Foo. Note that the annotation is not responsible for the behaviour and merely a compile-time check to ensure that there is a method void bar(String baz) in at least one parent-class.
The code presented has two method with same name, but different signatures. This is called Overloading in Java. Thus, the method are treated as not "equal". You could rename one of those method and they would not be more or less "equal".
To make things even weirder, if methods are overloaded, the signature for the method to call is made at compile-time. That means that only the static types of parameters can be considered. Let us look at the following code and figure out what the result is:
public class Test {
public static void main(final String... args) {
final String s = "foo";
final Object o = s;
print(s);
print(o);
}
private static void print(final String s) {
System.out.println("Called with String parameter");
}
private static void print(final Object o) {
System.out.println("Called with Object parameter");
}
}
Ideon demo
Now what is the static type of s? It is the type to the left, where s was declared, thus print(final String s) is called and "Called with String parameter" is printed. What is the static type of o? Again, it is the type to the left, where o was declard, and thus print(final Object o) is called and "Called with Object parameter" is printed out. One could argue that in this trivial example, the compiler could figure out that the type of o can only be String, but basing this behaviour on the ability of the compiler to recognize types at compile-time makes it only more confusing.
In java, the whole class is loaded before a method is executed.
This means that the second method is loaded/ready before the first method is executed and the first method is loaded/ready before the second method is executed.
This allows to call a method recursively, and to call a method that will be declared later.
Also, the method is overloaded.
In java, it's possible to create multiple methods with the same name in the same class if the parameters are different. The methods will be treated as different, deoending of the argument that are passed to the method.
In other words, the name alone does not define which method is called but the signature, including the parameters(not the return value)
public class Maryland extends State { Maryland() { /* null constructor */ }
public void printMe() { System.out.println("Read it."); }
public static void main(String[] args) {
Region mid = new State();
State md = new Maryland();
Object obj = new Place();
Place usa = new Region();
md.printMe();
mid.printMe();
((Place) obj).printMe();
obj = md;
((Maryland) obj).printMe();
obj = usa;
((Place) obj).printMe();
usa = md;
((Place) usa).printMe();
}
}
class State extends Region {
State() { /* null constructor */ }
public void printMe() { System.out.println("Ship it."); }
}
class Region extends Place {
Region() { /* null constructor */ }
public void printMe() { System.out.println("Box it."); }
}
class Place extends Object {
Place() { /* null constructor */ }
public void printMe() { System.out.println("Buy it."); }
}
Hi There.
I'm trying to understand the behaviour of the above main method which prints the following output when run.
Read it.
Ship it.
Buy it.
Read it.
Box it.
Read it.
I'm particularly struggling to understand the output of the last two printMe methods in the main function.
My understanding is that the first two print me operations will use there super classes printMe method as the objects have not been explicitly downcast to the sub class and thus are considered to be State and Region objects respectively by the Java compiler.
I also believe I understand the next two outputs in which the classes are downcast and thus the subclass printMe functions will override the superclass functions.
However I am struggling to understand what is occurring in the last two printMe methods. I can see that the variable obj is initially declared as an Object and then downcast as a Place is assigned a reference to the usa object(of type Place). So why is the output then of type region in this instance? I feel I am missing fundamental here in my understanding.
In Java, instance method calls follow inheritance. No matter what the reference type is, it will call the method of the type of the actual object.
The type of the reference only determine which methods the compiler knows you can call. e.g.
String hi = "Hello";
Object A = hi;
String hiToString = A.toString(); // calls String.toString();
int l = A.length(); // won't compile even though the String in A has a length() method.
Note: for static methods, the instance is ignored and it is the compile time type which determines which method is called.
In Java, non-static methods are called with late-binding, which means we cannot make sure which function it will call until run-time.
My understanding is that the first two print me operations will use there super classes printMe method as the objects have not been explicitly downcast to the sub class and thus are considered to be State and Region objects respectively by the Java compiler.
Explicitly downcast does nothing in this code. Downcast is actually performed.
Object md is still a reference to State and Object mid is a reference of Region. Compiler will never know which printMe() will be called. It only checks that State and Region classes have the function printMe() or not.
At run-time, when the md.printMe() is called, JVM will check the Runtime type information (RTTI) of md, and know it is a Object of State class. Therefore, the printMe() function in the State class is called, no matter what md is declared. (Of course, you need to override the printMe() in the State class. If you don't, State class will inherit the printMe() function from its superclass Place, and the printMe() function in Place class will be called. You can check this by removing the printMe() function in your State class.)
According to these rules, the output is reasonable.
The type cast in ((Place) obj).printMe() is needed just because in Object class, there's no printMe() function in it. Still, the compiler can't make sure which function ((Place) obj).printMe() will called, it is decided at run-time. For example, if you change your ((Maryland) obj).printMe(); to ((Place) obj).printMe();, the output is still the same.
For static methods, these rules will not fit. You can read more information about them with the keywords "Overloading, Overriding and Hiding". These terminologies will help you to understand the inheritance system in Java.
Here's a test practice question i came across, would appreciate your help in making me understand the concepts
Let Hawk be a subclass of Bird. Suppose some class has two overloaded methods void foo(Hawk
h) and void foo(Bird b). Which version would get executed in the call foo(x) after the
declaration Bird x = new Hawk();
Here's the code i have so far, could someone explain to me why foo(bird b) gets executed?
public class MPractice {
public static void main(String args[]) {
Bird x = new Hawk();
Third y = new Third();
y.foo(x);
}
}
public class Third {
void foo(Hawk h) {
System.out.println("Hawk");
}
void foo(Bird b) {
System.out.println("Bird");
}
}
When Java performs overload resolution for choosing methods, it uses that type of the variable, not the runtime type of the object, to choose the method. The type of x is Bird, so the Third method chosen is foo(Bird).
This is because polymorphism isn't involved here; we're not calling a potentially overridden method on the Bird variable x, we're just calling one of a set of overloaded methods on an unrelated class, Third.
At compile time, method invocation for overloaded methods is determined based on the type the method parameters and the compile time (or static) type of the method arguments.
In your case, Third#foo(..) can take a Hawk and it can take a Bird. In your invocation
y.foo(x);
the compile time (or static) type of the argument x is Bird, since that's how it's declared, so the Third#foo(Bird) method will be invoked.
Consider this:
class A {
int x =5;
}
class B extends A{
int x =6;
}
public class CovariantTest {
public A getObject() {
return new A();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
CovariantTest c1 = new SubCovariantTest();
System.out.println(c1.getObject().x);
}
}
class SubCovariantTest extends CovariantTest {
public B getObject(){
return new B();
}
}
As far as I know, the JVM chooses a method based on the true type of its object. Here the true type is SubCovariantTest, which has defined an overriding method getObject.
The program prints 5, instead of 6. Why?
The method is indeed chosen by the runtime type of the object. What is not chosen by the runtime type is the integer field x. Two copies of x exist for the B object, one for A.x and one for B.x. You are statically choosing the field from A class, as the compile-time type of the object returned by getObject is A. This fact can be verified by adding a method to A and B:
class A {
public String print() {
return "A";
}
}
class B extends A {
public String print() {
return "B";
}
}
and changing the test expression to:
System.out.println(c1.getObject().print());
Unless I'm mistaken, methods are virtual in java by default, so you're overriding the method properly. Fields however (like 'x') are not virtual and can't be overriden. When you declare "int x" in B, you are actually creating a totally new variable.
Polymorphism doesn't go into effect for fields, so when you try and retrieve x on an object casted to type A, you will get 5, if the object is casted to type B, you will get 6.
When fields in super and subclasses have the same names it is referred to as "hiding". Besides the problems mentioned in the question and answer there are other aspects which may give rise to subtle problems:
From http://java.sun.com/docs/books/tutorial/java/IandI/hidevariables.html
Within a class, a field that has the
same name as a field in the superclass
hides the superclass's field, even if
their types are different. Within the
subclass, the field in the superclass
cannot be referenced by its simple
name. Instead, the field must be
accessed through super, which is
covered in the next section. Generally
speaking, we don't recommend hiding
fields as it makes code difficult to
read.
Some compilers will warn against hiding variables