What does Java `this` actually refer to in an inheritance situation? - java

Why does the following Java code produces:
10
superclass
The code in question is:
class SuperClass {
int a;
public SuperClass() {
this.a = 10;
}
private void another_print() {
System.out.println("superclass");
}
public void print() {
System.out.println(this.a);
this.another_print();
}
}
class SubClass extends SuperClass {
int a;
public SubClass() {
this.a = 20;
}
private void another_print() {
System.out.println("subclass");
}
public void print() {
super.print();
}
}
public class Main {
public static void main (String[] args) {
SubClass c = new SubClass();
c.print();
}
}
There is no instance of SuperClass ever created, isn't there?
Not only that Java starts looking for the method to invoke from the SuperClass, it even somehow knows that a = 10!
Let's consider a similar Python code:
class SuperClass:
def __init__(self):
self.a = 10
def another_prn(self):
print('superclass')
def prn(self):
print(self.a)
self.another_prn()
class SubClass(SuperClass):
def __init__(self):
self.a = 20
def another_prn(self):
print('subclass')
def prn(self):
super().prn()
c = SubClass()
c.prn()
It works as I expect:
20
subclass
The only explanation that my colleagues (Python disliking Java folks) came up with is: "Python is not a true OOP language". Not very convincing at all.
Update: private void another_print() is my blunder, I should have used protected.

It is the order of constructor calling in Java.
In the SubClass, when you instantiate c, the constructor implicitly calls the default constructor of the SuperClass (public SuperClass()) (it must do so). Then a is set to be 10 in the SuperClass.
Now that we're done with the SuperClass constructor, we get back to the constructor of SubClass, which assigns a = 20. But fields are not subject to overriding in java, so a in SuperClass is still 10.
After that it's pretty obvious, we call c.print() which calls the print of SubClass, which calls the print of SuperClass (by super.print()), which prints a which is as you remember 10. Then another_print (which is not overridden since it is private) just prints superclass and we're done.

In the sub-class's print you just call super-class's print method.
So it prints the a from the super class of course.
You have two separate a fields here. Fields are not subject to overriding, only methods are. The super-class has an a field and you have another a field in the sub-class.
If another language produces another result, that's not a big surprise. Also, I am not sure your Python code is logically equivalent/analogous to your Java code.

My comment explained the reason your code probably doesn't work as expected.
Below is code written how you most likely expected it to work. Note the comments in the code.
static class SuperClass {
int a; // only declare field in superclass to avoid hiding
public SuperClass() {
this.a = 10;
}
// make method protected, public, or package private to allow children to override it
protected void another_print() {
System.out.println("superclass");
}
public void print() {
System.out.println(this.a);
this.another_print();
}
}
static class SubClass extends SuperClass {
public SubClass() {
this.a = 20;
}
#Override
protected void another_print() {
System.out.println("subclass");
}
public void print() {
super.print();
}
}
public static void main (String[] args) {
SubClass c = new SubClass();
c.print();
}
This will print
20
subclass

I've debugged my slightly corrected code and found out that:
this is an instance of SubClass
Unlike Python, Java is ok with more than one variable of the same name (as peter.petrov mentioned in his answer, but I didn't got it right away)
One of the as is from the SubClass and the second is from the SuperClass (as implicit superclass constructor call, again unlike Python)
this.a has a different value in test_super() and test_sub() and that is the magic, given that this is a SubClass and Java documentation reads:
this is a reference to the current object — the object whose method or constructor is being called
I think I can live with the fact that this will have all the variables from the whole dependency tree and Java will select which one to use depending on the context.

Related

How to force my subclass constructor not to call base class constructor?

public class Base {
public Base() {
foo();
}
public void foo() {
System.out.println("Base.foo()");
}
}
public class Derived extends Base {
public Derived () {}
public void foo() {
System.out.println("Derived.foo()");
}
}
And then, when i call those:
public class Running {
public static void main(String[] args) {
Base b = new Base();
Derived d = new Derived();
}
}
It outputs:
*Base.foo()*
*Derived.foo()*
So why, when it gets to derived constructor, it invokes the base constructor but uses the derived's method instead?
PS: If I mark those methods as private, it will print out:
*Base.foo()*
*Base.foo()*
This is how Java works read this page https://docs.oracle.com/javase/tutorial/java/IandI/super.html
And more specifically the Note here :
Note: If a constructor does not explicitly invoke a superclass
constructor, the Java compiler automatically inserts a call to the
no-argument constructor of the superclass. If the super class does not
have a no-argument constructor, you will get a compile-time error.
Object does have such a constructor, so if Object is the only
superclass, there is no problem.
So as you can see this is expected behavior. Even though you dot have a super call it is still automatically inserting it.
In regards of the second Question even though you are within the super constructor body still you Instance is of the Subtype. Also if you have some familiarity with C++ read this Can you write virtual functions / methods in Java?
The reason why it will write the base class when marking with private is because private methods are not Inherited. This is part of the Inheritance in Java topic.
To answer the question in your title. As I said, you cannot avoid the base class constructor being called (or one of the base class constructors if it has more than one). You can of course easily avoid the body of the constructor being executed. For example like this:
public class Base {
public Base(boolean executeConstructorBody) {
if (executeConstructorBody) {
foo();
}
}
public void foo() {
System.out.println("Base.foo()");
}
}
public class Derived extends Base {
public Derived() {
super(false);
}
public void foo() {
System.out.println("Derived.foo()");
}
}
public class Running {
public static void main(String[] args) {
Base b = new Base(true);
Derived d = new Derived();
}
}
Now the main method prints only:
Base.foo()
Because in the contructor of the Derived class it automatically gets injected a call to super(), if you do not add a call to super or to other constructor in the same class (using this).

overriding protected method of Superclass

In the below example why does the String b prints null and String c prints "gg".
Correct me if I am wrong, whenever a subclass (BClass) overrides a protected method (i.e initClass()) of the superclass (AClass).If you instantiate the subclass. The superclass must make use of overriden method specified by the subclass.
public class Example {
public class AClass {
private String a;
public AClass() {
initClass();
}
protected void initClass() {
a = "randomtext";
}
}
public class BClass extends AClass {
private String b = null;
private String c;
#Override
protected void initClass() {
b = "omg!";
c = "gg";
}
public void bValue() {
System.out.println(b); // prints null
System.out.println(c); // prints "gg"
}
}
public static void main(String[] args) {
Example.BClass b = new Example().new BClass();
b.bValue();
}
}
As of the JSF 12.5
In the example you can see the execution order. The first steps are the callings of the Constructor down to the Object constructor.
Afterwards this happens:
Next, all initializers for the instance variables of class [...] are executed.
Since your instance variable b is initialized to null it will be null again afterwards
This is happening because the superclass constructor is called before the fields of ClassB is initialized. Hence the initClass() method is called which sets b = "omg!" but then again when the super class constructor returns, b is initialized to the value declared in ClassB which is null.
To debug, put a break point and go step by step, you will find that b is first set to null and then changes to omg! and then comes back to null.
There have been already given several correct answers about what's happening. I just wanted to add that it is generally bad practice to call overridden methods from constructor (except of course if you know exactly what you are doing). As you can see, the subclass may not be completely initialised at the time its instance method is invoked (subclass constructor logic has not been executed yet, so effectively overridden method is invoked on an unconstructed object which is dangerous) which might lead to confusions like the one described in this question.
It is much better to write initialisation logic in the constructor and if it is too long then divide it between several private methods invoked from the constructor.
This is happening like this because, first constructor of AClass, which set value of b = omg! and c=gg. After that When BClass gets load in memory it set b=null and c remain as it is which is gg, this is happening because, because in BClass, for b you are doing declaration as well as initialization and for c you are doing only declaration, so as c is already in the memory it even won't get it's default value and as you are not doing any initialization for c, it remain with it's earlier state.
I believe that this example explains the issue:
public class Main {
private static class PrintOnCreate {
public PrintOnCreate(String message) {
System.out.println(message);
}
}
private static class BaseClass {
private PrintOnCreate member =
new PrintOnCreate("BaseClass: member initialization");
static {
System.out.println("BaseClass: static initialization");
}
public BaseClass() {
System.out.println("BaseClass: constructor");
memberCalledFromConstructor();
}
public void memberCalledFromConstructor() {
System.out.println("BaseClass: member called from constructor");
}
}
private static class DerivedClass extends BaseClass {
private PrintOnCreate member =
new PrintOnCreate("DerivedClass: member initialization");
static {
System.out.println("DerivedClass: static initialization");
}
public DerivedClass() {
System.out.println("DerivedClass: constructor");
}
#Override
public void memberCalledFromConstructor() {
System.out.println("DerivedClass: member called from constructor");
}
}
public static void main (String[] args) {
BaseClass obj = new DerivedClass();
}
}
The output from this program is:
BaseClass: static initialization
DerivedClass: static initialization
BaseClass: member initialization
BaseClass: constructor
DerivedClass: member called from constructor
DerivedClass: member initialization
DerivedClass: constructor
... which demonstrates that the derived class's members are initialized after the base class's constructor (and the invocation of the derived class's member function have completed). This also demonstrates a key danger of invoking an overridable function from a constructor, namely that the function can be invoked before the members of the class on which it depends have been initialized. For this reason, constructors should generally avoid invoking member functions (and, when they do, those functions should either be final or static, so that they either depend only on the current class which has been initialized or on none of the instance variables).

Why doesn't the compiler complain when I try to override a static method?

I know that we cannot override static methods in Java, but can someone explain the following code?
class A {
public static void a() {
System.out.println("A.a()");
}
}
class B extends A {
public static void a() {
System.out.println("B.a()");
}
}
How was I able to override method a() in class B?
You didn't override anything here. To see for yourself, Try putting #Override annotation before public static void a() in class B and Java will throw an error.
You just defined a function in class B called a(), which is distinct (no relation whatsoever) from the function a() in class A.
But Because B.a() has the same name as a function in the parent class, it hides A.a() [As pointed by Eng. Fouad]. At runtime, the compiler uses the actual class of the declared reference to determine which method to run. For example,
B b = new B();
b.a() //prints B.a()
A a = (A)b;
a.a() //print A.a(). Uses the declared reference's class to find the method.
You cannot override static methods in Java. Remember static methods and fields are associated with the class, not with the objects. (Although, in some languages like Smalltalk, this is possible).
I found some good answers here: Why doesn't Java allow overriding of static methods?
That's called hiding a method, as stated in the Java tutorial Overriding and Hiding Methods:
If a subclass defines a class method with the same signature as a
class method in the superclass, the method in the subclass hides the
one in the superclass.
static methods are not inherited so its B's separate copy of method
static are related to class not the state of Object
You didn't override the method a(), because static methods are not inherited. If you had put #Override, you would have seen an error.
A.java:10: error: method does not override or implement a method from a supertype
#Override
^
1 error
But that doesn't stop you from defining static methods with the same signature in both classes.
Also, the choice of method to call depends on the declared type of the variable.
B b = null;
b.a(); // (1) prints B.a()
A a = new B();
a.a(); // (2) prints a.a()
At (1), if the system cared about the identity of b, it would throw a NPE. and at (2), the value of a is ignored. Since a is declared as an A, A.a() is called.
Your method is not overridden method. you just try to put #Override annotation before your method in derived class. it will give you a compile time error. so java will not allow you to override static method.
While goblinjuice answer was accepted, I thought the example code could improved:
public class StaticTest {
public static void main(String[] args) {
A.print();
B.print();
System.out.println("-");
A a = new A();
B b = new B();
a.print();
b.print();
System.out.println("-");
A c = b;
c.print();
}
}
class A {
public static void print() {
System.out.println("A");
}
}
class B extends A {
public static void print() {
System.out.println("B");
}
}
Produces:
A
B
-
A
B
-
A
If B had overridden print() it would have write B on the final line.
Static methods will called by its Class name so we don't need to create class object we just cal it with class name so we can't override static
for example
class AClass{
public static void test(){
}
}
class BClass extends AClass{
public static void test(){}
}
class CClass extends BClass{
public static void main(String args[]){
AClass aclass=new AClass();
aclass.test(); // its wrong because static method is called
// by its class name it can't accept object
}
}
we just call it
AClass.test();
means static class can't be overridden
if it's overridden then how to cal it .
Static members belong to class not to any objects. Therefore static methods cannot be overriden. Also overiding happens at run time therefore compiler will not complain.
Howeve, you can add #Override annotation to method. This will flag compiler error.

Accessing properties in a super class using super or this in the subclass?

In terms of values for properties defined in the super class using the same property in the sub-class and the property is defined as protected, then using super or this does not make any difference right ? Then why does the language really have these ways of accessing the properties ? Is there a scenario where they will have different values.
class A{ protected int a = 15;
}
class B{
public void printA()
{
System.out.print(super.a) // prints 15
System.out.print(this.a) // prints 15
}
}
In this situation, it doesn't make any difference. However, as soon as you change to methods instead of variables, and introduce another method in B which shadows the one in A, then it makes a difference:
class A {
protected int a = 15;
}
class B extends A {
private int a = 10;
public void printA() {
System.out.println(super.a); // prints 15
System.out.println(this.a); // prints 10
}
}
This is more common with methods than with fields though - often an overriding implementation needs to call the superclass implementation as part of its implementation:
public void foo() {
super.foo();
// Now do something else
}
I would personally recommend avoiding non-private fields, at which point the field part becomes irrelevant.
See section 6.4.1 of the JLS for more on shadowing.

OOP inheritance execution

Why does the execution of TestClass.main() outputs 202 202 101??
class BaseClass
{
int data = 101;
public void print()
{
System.out.print(data + " ");
}
public void fun()
{
print();
}
}
class SubClass extends BaseClass
{
int data = 202;
public void print()
{
System.out.print(data + " ");
}
}
class TestClass
{
public static void main(String[] args)
{
BaseClass obj = new SubClass();
obj.print();
obj.fun();
System.out.print(obj.data);
}
}
With my poor OOP knowledge I think the execution must be this way:
1- obj.print(); prints 202 from SubClass
2- Since there is no obj.fun(); method in Subclass it calls parent method so the output should be 101
3- System.out.print(obj.data); should print 202 since the value is overridden in subclass.
So I think the output would be 202 101 202 but it isn't, can you explain me why?
Since there is no obj.fun(); method in Subclass it calls parent method so the output should be 101
Indeed, it calls the super class for fun, but the super class calls print, and as print is overridden, the overriding version (in the subclass) gets called.
System.out.print(obj.data); should print 202 since the value is overwritten in subclass.
Variables are not overriden, but hidden by subclass, as obj declared as BaseClass, it accesses it data property directly. unlike method call, this is decided at compile time.
Because method are polymorphic and fields are not
if you remove
int data = 101;
from your BaseClass it will not compile
The trick is in deciding which method is executed. That choice is made from the type of the instance of the object. In your case, obj is a SubClass and every call to print() will execute the print method of SubClass. This mechanism is called Polymorphism in OOP.
Instead of mixing methods and variables, I'd recommend you start by just doing some testing on methods only. The code is mostly the same, with the same Polymorphism behavior, but without the variables.
class BaseClass
{
public void print()
{
System.out.print(101 + " ");
}
public void fun()
{
print();
}
}
class SubClass extends BaseClass
{
public void print()
{
System.out.print(202 + " ");
}
}
class TestClass
{
public static void main(String[] args)
{
BaseClass obj = new SubClass();
obj.print();
obj.fun();
}
}
1 and 2 - methods are polymorphic - method from base class will use method from sub class, if it will be able and ofc if you have reference to sub class
3 - field isnt polymorphic. It's taken from the type of reference.

Categories

Resources