I am studying for my OCA exam and came across this problem and It is very confusing.
Variable resolution always based on reference type instead of the runtime object. So if my parent and child class look like this:
class Parent {
public int x = 1;
public int getX() {
return x;
}
}
class Child extends Parent {
public int x = 2;
public int getX() {
return x;
}
}
Based on the rules (variable resolution is always based on reference type), the following code is behaving as expected:
Child c = new Child();
System.out.println(c.x); //2
System.out.println(((Parent) c).x); //1
However. if I retrieve the variables by using the getter defined in the parent and child class, then I get this:
Child c = new Child();
System.out.println(c.getX()); //2
System.out.println(((Parent) c).getX()); //2
Shouldn't it print the same as if I was to access the variable directly? why would getting the variable via getter be different than getting the variable directly?
One theory I have is this:
Since instance method resolution is based on runtime object, therefore it overrides the variable resolution rule. In other words, the compiler will resolve the getter methods to the child class since instance method resolution is based on runtime object. Am I right?
Thank you
Methods and variables behave differently. Variables do not get inherited or participate in polymorphism.
The Parent and Child classes each have their own distinct variable x. One doesn't override the other. You can use the cast to specify that you want the Parent's x, not the Child's.
With the method, it doesn't matter what cast you stick on it, when calling the Child you get the overridden version of getX. (Within a method of the Child you can call super.getX to get the parent's version of the method.)
TLDR: variable resolution rules don't apply to methods. Polmorphism doesn't apply to variables.
System.out.println(((Parent) c).getX()); //2
This dispatches to Child.getX() because of polymorphism. Then the variable resolution rules apply in the context of this method. They aren't overridden. So yes, you are essentially correct.
Polymorphism is a mechanism applied before calling a method, which always looks for the most specific override in the whole chain of subclasses, regardless of the instance's declared type.
There is no such mechanism for fields. Giving the two variables the same name "x" does not connect them in any way, so giving those two fields the same name will likely only serve to confuse future readers of your code.
Related
public class Main {
public static void main(String[] args) {
Parent p = new Child();
System.out.println(p.x); // 10 is printed
System.out.println(p.print()); // Child is printed
}
}
class Parent{
int x = 10;
public String print(){ return "Parent";}
}
class Child extends Parent{
int x = 55;
public String print(){ return "Child"; }
}
Why Dynamic Method Dispatch is not working on properties ?
Is there any purpose, meaning or it was just designed like that.
Effectively? Because unlike methods, fields cannot be overridden. Fundamentally: It makes no sense.
When you override a method, it is not about just the name. Only if everything matches, does it count. Let's try this:
public class Example {
#Override public boolean equals(Example other) { return false; }
}
The above will not compile because that is not the same as Object's own equals. The parameter type doesn't match. As a language syntax sugar nicety to you, you may 'widen' your specs (you can specify a more specific return type, and a more general parameter type, and you can elect to declare fewer checked exceptions), but if you inspect a class file, you'll find the exact method signature of your parent class in your own.
Expanding that notion to fields, a field isn't just the name. It's the name and its type.
When you declare int x; in class Parent, that field exists in all instances of Parent, including any instances of a subclass of Parent. In other words, your class Child extends Parent class already has an x field. There's nothing you can do to change its essence. That's in sharp contrast to methods, where you can redefine what it does by changing the code. This just doesn't apply to fields: Fields don't have code.
Because of all that, when you declare a method that has the same signature as a method declaration of a parent, that is an override, but:
When you declare a field that has the same signature (same name, same type) as a parent class's field, you are declaring a second, separate field whose name shadows the field of the parent.
The behaviour is just completely different. The simple solution is to simply not declare int x, at all, in child. Write into parent's x, if you must. The above explains why this behaviour is so very different.
Writing classes that participate in an inheritance hierarchy is hard. We need the classes to expose behavior and allow customization by subclasses, but without allowing subclasses to change things the superclass is counting on. Allowing subclasses to override methods, but keeping superclass state private accomplishes this separation.
However, if subclasses can override variables in a superclass then the superclass can’t have confidence in the variables it needs to manipulate and the subclasses can tamper with the superclass. The superclass may work or not, depending on what extends it.
If this was a feature, and you had the option to use it or not, similar to using a keyword like virtual in C# but for methods, when would you use it? I can’t think of a case where it would make sense.
I was having an exam in Java today and the examiner asked me if I can provide any examples of using polymorphism in my Spring Boot project.
As I couldn`t think of anything at first, he pointed out that I have overriden toString() in my models and that this is dynamic/runtime polymorphism.
However, I am not sure that I understand his point, because to my understanding, a behavior is considered polymorphmic when we have a parent class reference variable pointing to a subclass object (focusing on dynamic polymorphism).
Then at runtime the actual object, to which the parent class variable points to, is fetched and its method is called, as explained nicely here.
However, I do not use upcasting in my project (i.e. initializing my POJO classes with an Object class variable).
Thus, my question is - is overriding toString() considered polymorphism, although the parent class (Object) is never used as a reference variable?
All exampes of runtime polymorphism that I find on Stackoverflow, including the ones here and this one with toString, illustrate a situation where we have a parent class variable pointing to a subclass object, e.g:
Object object = new User("petar");
String name = object.toString(); // assign to variable for clarity`s sake
System.out.println(name);
// prints petar
Where my User class is:
public class User {
String name;
public User(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
However, in my project I simply create users and other POJO classes with their own reference variables, e.g:
User user = new User("petar");
String name = user.toString();
System.out.println(name);
// prints petar, as toString is overriden
Is the above considered polymorphism, although there is no upcasting / parent reference variable involved?
My classmate argues that it is, because for non-final instance methods, the compiler doesn`t know which method to call - it only ensures that there is such method in the superclass, so it prolongs this decision up until runtime (late binding) by inserting an instruction into the compiled code, which is checked then and the actual object, to which the variable points to, is fetched, and its method is called (source).
However, in this article it is stated that:
Method Overriding is an example of runtime polymorphism. When a parent
class reference points to the child class object then the call to the
overridden method is determined at runtime, because during method call
which method(parent class or child class) is to be executed is
determined by the type of object. This process in which call to the
overridden method is resolved at runtime is known as dynamic method
dispatch.
So: is method overriding sufficient for polymorphism, or is it a requirement that there is a parent class reference to the subclass object? Am I safe to say at interviews that merely overriding toString() is an example of polymorphism?
Thanks to the comments and a few other sources, I believe I can now answer my question as follows:
One could argue that overriding toString() is an example of polymorphism because:
The Java Virtual Machine (JVM) always selects the method to invoke on non-final instance methods based on the object that it is referenced to, and not the method defined by the variable type. This is known as dynamic method invocation or late binding i.e - the decision which method to call happens at runtime, hence the wording "runtime" polymorphism. Source: Oracle Docs, JavaWorld.
Thus, regardless whether we consciously use polymorphism by e.g. programming to interfaces or we do a simple toString() method override, but still continue to use our classes with their own class variables (i.e. using a "User" variable instead of the parent class "Object" variable), a decision about which method to call is always made on runtime by checking the type of object our variables are referring to.
Thus, the evaluation on which model to call (i.e. the polimorphic behavior) happens, regardless which of the two initializations we use:
User user = new User("username1");
System.out.println(user);
// or
Object object = new User("username1");
System.out.println(object);
The type of the variable is insignificant for our question, what matters is the object that it is referring to, and which of all possible objects it refers to (i.e a parent or a child), is decided on runtime.
The type of the variable is only relevant to either limit the scope of available methods to the ones in the parent class and potentially overridden by its children (if we use a parent class reference variable) or to gain access to the specific methods of the child (if we use a child class reference variable).
For example, if we added a new method to our User class:
public String instanceMethod () {
return "User instance method called";
}
It would not be available through a Object class variable:
It would only be available through a User class variable.
Hope this clears the confusion for everyone else that needs a more detailed explanation too.
I want to know the difference between accessing parent class fields using this and super.
We have the following abstract class named ListItem which extends Node class.
public abstract class ListItem {
protected ListItem rightLink=null;
abstract ListItem next();
}
And the following code inside the Node class:
public class Node extends ListItem {
#Override
ListItem next() {
return this.rightLink;
}
But if we use the code super.rightLink, I do not get any error at compile time or runtime. I just want to know what is the difference between the both and is there a best practice to accomplish the task?
Explanation
It does not matter in this case, there is no difference.
The field is declared in the parent class. So technically super.rightLink would makes the most sense. However, super and this are only relevant for resolving ambiguous situations with variable shadowing.
The best in this case would be to leave out any prefix and just type rightLink. But this is a bit opinion-based.
Example
Suppose we have the following
public class Parent {
int variable = 1; // Field
}
public class Child extends Parent {
int variable = 2; // Field
public void foo() {
int variable = 3; // Local variable
System.out.println(variable); // 3
System.out.println(this.variable); // 2
System.out.println(super.variable); // 1
}
}
In-depth
So we have a situation with 3 different variables which all live in a different scope, but they have the same name. When you just type variable, Java will refer to the variable with the lowest scope. Which would be the local variable in the method.
If you want to access your field, you need to do this.variable. If you want to access the field of your parent, you need to do super.variable.
So again, we have three different variables here.
no prefix: lowest scope
this: field with lowest scope
super: field with lowest scope, starting from the direct parent
In your specific example, however, we have no name shadowing at all. There is only one variable with the name rightLink. So all three variants refer to the exact same variable.
The best in this case would be to use no prefix at all, just rightLink.
JLS
Let us see how the Java Language Specification defines this. and super..
For this., refer to JLS§15.8.3:
When used as a primary expression, the keyword this denotes a value that is a reference to the object for which the instance method or default method was invoked (§15.12), or to the object being constructed. The value denoted by this in a lambda body is the same as the value denoted by this in the surrounding context.
For super., refer to JLS§15.11.2:
The form super.Identifier refers to the field named Identifier of the current object, but with the current object viewed as an instance of the superclass of the current class.
Unless rightLink is marked as private, it will be accessible in all classes deriving from ListItem. Thus, call super.rightLing and this.rightLink will be equivalent.
Generally, super refers to base class and this refers to class you are in. Use them appropraitely.
It's commonly used when overriding methods, i.e.
#Override
public void DoSomething(){
// Execute base imlpementation of a method
super.DoSomething();
// some additional code to add extra functionality to base class
}
I'm wondering why Java has this strange behavior regarding a superclass and a subclass having instance variables with the same name.
Let's say we have the following class definitions:
class Parent {
int var = 1;
}
class Child extends Parent {
int var = 2;
}
By doing this, we are supposed to have hidden the superclass's variable var. And if we do not explicitly specify a way to access Parent's var via a super call, then we should never be able to access var from an instance of a child.
But when we have a cast, this hiding mechanism breaks:
Child child = new Child();
Parent parent = (Parent)child;
System.out.println(parent.var); // prints out 1, instead of 2
Doesn't this completely circumvent the whole point of field hiding? If this is the case, then doesn't that render the the idea completely useless?
EDIT: I am referring specifically to this article in the Java Tutorials. It mentions
Within the subclass, the field in the superclass cannot be referenced
by its simple name. Instead, the field must be accessed through super...
From what I read there, it seems to imply that the developers of Java had some kind of technique in mind in doing this. Though I agree that it is a rather obscure concept and would probably bad practice in general.
In Java, data members are not polymorphic. This means that Parent.var and Child.var are two distinct variables that happen to have the same name. You're not in any sense "overriding" var in the derived class; as you have discovered yourself, both variables can be accessed independently of one another.
The best way forward really depends on what you're trying to achieve:
If Parent.var should not be visible to Child, make it private.
If Parent.var and Child.var are two logically distinct variables, give them different names to avoid confusion.
If Parent.var and Child.var are logically the same variable, then use one data member for them.
The "point" of field hiding is merely to specify the behaviour of code which does give a variable the same name as one in its superclass.
It's not meant to be used as a technique to genuinely hide information. That's done by making the variables private to start with... I would strongly recommend using private variables in virtually all cases. Fields are an implementation detail which should be hidden from all other code.
Attributes are not polymorphic in Java, and anyway declaring a public attribute is not always a good idea. For the behavior you're looking for, it's better to use private attributes and accessor methods, like this:
class Parent {
private int var = 1;
public int getVar() {
return var;
}
public void setVar(int var) {
this.var = var;
}
}
class Child extends Parent {
private int var = 2;
public int getVar() {
return var;
}
public void setVar(int var) {
this.var = var;
}
}
And now, when testing it, we get the desired result, 2:
Child child = new Child();
Parent parent = (Parent)child;
System.out.println(parent.getVar());
This scenario is known as variable hiding, When the child and parent class both have a variable with the same name, child class's variable hides parent class's variable and this process is called variable hiding.
In Java variables are not polymorphic and Variable Hiding is not same as Method Overriding
While variable hiding looks like overriding a variable similar to method overriding but it is not, Overriding is applicable only to methods while hiding is applicable variables.
In the case of method overriding, overridden methods completely replaces the inherited methods so when we try to access the method from parent's reference by holding child's object, the method from child class gets called.
But in variable hiding child class hides the inherited variables instead of replacing, so when we try to access the variable from parent's reference by holding child's object, it will be accessed from the parent class.
public static void main(String[] args) throws Exception {
Parent parent = new Parent();
parent.printInstanceVariable(); // Output - "Parent`s Instance Variable"
System.out.println(parent.x); // Output - "Parent`s Instance Variable"
Child child = new Child();
child.printInstanceVariable();// Output - "Child`s Instance Variable, Parent`s Instance Variable"
System.out.println(child.x);// Output - "Child`s Instance Variable"
parent = child; // Or parent = new Child();
parent.printInstanceVariable();// Output - "Child`s Instance Variable, Parent`s Instance Variable"
System.out.println(parent.x);// Output - Parent`s Instance Variable
// Accessing child's variable from parent's reference by type casting
System.out.println(((Child) parent).x);// Output - "Child`s Instance Variable"
}
As we can see in above when an instance variable in a subclass has the same name as an instance variable in a superclass, then the instance variable is chosen from the reference type.
Declaring variables with the same name in both child and parent create confusion we should always avoid it so there will be no confusion. And this is why we should also always stick to General Guidelines to create POJOs and declare our variables with private access and also provide proper get/set methods to access them.
You can read more on my article What is Variable Shadowing and Hiding in Java.
When you are casting, you effectively tell the compiler "I know better" - it suspends the normal strong-typing inference rules and gives you the benefit of a doubt.
By saying Parent parent = (Parent)child; you are telling the compiler "treat this object as if it were an instance of Parent".
On another note, you are confusing "information hiding" principle of OO (good!) with a field-hiding side-effect (usually bad).
As you pointed out:
we are supposed to have hidden the superclass's variable var
The main point here is Variables do not override as methods do, so when you call directly Child.var you are calling a variable directly from the Child class and when you call Parent.var you're calling a variable from the Parent class, no matter if they do have the same name.
As a side note I would say this is really confusing and shouldn't be allowed as valid syntax.
Consider the following illegal code :-
class WrongCode{
int i;
static int i;
}
Here, the compiler says that we have duplicate fields in the same class.
Now, consider the following classes in the same file.
class Parent{
int i = 10;
}
class Child extends Parent{
static int i = 100;
}
public class Main{
public static void main(String ... aaa){
Parent ob = new Child();
System.out.println(ob.i); // This prints Parent's i
}
}
Since the actual object is of Child, shouldn't ob refer to Child's i? And if it is refering to Parent's "i", then in a way it is also having Parent's "i" in its own class along with its own static "i" which is NOT ALLOWED.
Child static i overshadows Parent i. And Parent's i is not static, so then how is it accessed directly using instance and not className?
You have instance field i in Parent class and it remain an instance field in Child class.
System.out.println(ob.i); // must be 10
Have a look at - Oracle Java Tutorial - Hiding Fields
It is important to realize here that there is no way System.out.println(ob.i); could print Child's i: it only knows that ob is of declared type Parent, not that it was instantiated with an actual Child. Thus, if Parent did not have any i, there would be a compile error. If parent has an i, this is printed.
I have seen it mentioned on SO that access of class variables via instances (i.e. ob.i being equivalent to Parent.i) should be considered a serious design flaw of Java. I agree it can be sometimes confusing. Anyway, both your parent and child could also have a non-static i and it need not be the same. The argument above should be applicable to reasoning which one would be printed in which situation.
In ob, the static int i of child is never visible since ob is of type Parent, irrespective of how it was instantiated( base class or derived class).
That's why you have the value as 10, that Parents i value.
When you access class member fields (instance variables) like ob.i. you'll get the results from the class that's known at compile time, not what is known at run time. Thats why you have value as 10 which is parents value.
For method calls they are dispatched at run time to an object of the actual class the reference points.
Regarding shadowing here is what Java lang spec says:
If the class declares a field with a certain name, then the declaration of that field is said to hide any and all accessible declarations of fields with the same name in superclasses, and superinterfaces of the class.
A hidden field can be accessed by using a qualified name (if it is static)
language spec
You may refer "Field Declarations" section.
Actually its polymorphism and ob have access only to parent class fields and behaviuors if any...
Java lets your class have its own variables that have the same name as a variable in the parent. But it can't just let you randomly redefine parent variables, as that would cause other stuff to break. So what it does...when you have a variable obj that's declared as the parent class, even if it holds an instance of a child class, obj.i will refer to the parent class's i rather than the child's.