0

I have couple questions regarding accessing public fields with inheritance. Considering below example.

public class SuperClass {
    public int x;
    // setter and getter methods for x
    ...
}
public class SubClass extends SuperClass {
    public int x;
    @Override
    // setter and getter methods for x (both override superclass methods)
    ...
}

// inside main():
System.out.println("When using set method: ");
SubClass f = new SubClass(); 
f.setX(10);
((SuperClass) f).setX(100);

System.out.println("super: " + ((SuperClass)f).x);
System.out.println("subclass: " + f.x);

System.out.println("\nWhen changing field directly:");

f.x = 10;
((SuperClass) f).x = 100;
System.out.println("super: " + ((SuperClass)f).x);
System.out.println("subclass: " + f.x);

which prints out as:

When using set method: // why are the variable values swapped?
super: 10
subclass: 100

When changing field directly: // these results are within expectation
super: 100
subclass: 10

I thought that casting will only affect how compilers treat the object, and during execution time object will access its fields and methods based on how the object is initialized without consider what type/class it is.

However I feel my understanding towards this subject might be incomplete or plainly wrong.

Question 1: In the first case scenario (using set method), why does the result looks like that? More specifically, I want to know how does setting and invoking public fields directly work, and when is this done (execution time or compiler time)?

Question 2: where/how is super class's hidden fields stored? I'm asking this because it looks like superclass's fields are stored seperately from the subclass, even though they should be the same by using just casting. Since the compiler allocated memory for just a single normal subclass object, I don't see how there's extra space to store superclass's information.

The situation is more confusing when declared object f as Superclass but instantiated as Subclass.

I'm running this on JDK 11.0.2

halfer
  • 19,824
  • 17
  • 99
  • 186
Jason
  • 15
  • 1
  • 5
  • 1
    Can you post the definitions of the two classes? Sounds like sub and super class both have a field called x – Joni Mar 27 '20 at 01:23
  • 3
    You have **two** fields named `x`. Don't do that. `SubClass` ***inherits*** one `x`, and then you explicitly added another field with the same name (which ***shadows*** the first one). So it has **two** `x`(s). – Elliott Frisch Mar 27 '20 at 01:27
  • Also, can't replicate your output: [ideone](https://ideone.com/wwglaZ) – Johannes Kuhn Mar 27 '20 at 01:30
  • @JohannesKuhn I ran your code and it looks like you have to put those two classes and the main function in three different files to let it work. So it doesn't behave the same way for inner classes I guess. – Jason Mar 27 '20 at 01:37
  • @ElliottFrisch I did notice there are two X's, but that doesn't explain the behavior though. – Jason Mar 27 '20 at 01:39
  • No, that has nothing to do with that... well, except if... no, they are both public. [New ideone](https://ideone.com/9xe1GA) – Johannes Kuhn Mar 27 '20 at 01:39
  • @JohannesKuhn run that in an IDE with 3 separate files and it should display that...Unless the compiler version affects the outcome. I'm using JDK 11.0.2 – Jason Mar 27 '20 at 01:46
  • @Jason It does. You just confused yourself. Rename the `x`(s) to anything meaningful and your confusion should go away (especially if you pick unique names). – Elliott Frisch Mar 27 '20 at 01:47
  • @ElliottFrisch You are absolutely right. However, I'm trying to make sense out of this so that I can have a deeper understanding about how Java compiler works – Jason Mar 27 '20 at 01:50
  • @Jason **Hint** The compiler does not treat `x` any different than `fred`. So variable names do nothing for the **compiler**. If you really want to understand how compilers work, read about compilers. Don't try and create corner cases in an existing language like Java. It has a compiler. And the compiler it has is not a good place to **start** learning about compilers in general. – Elliott Frisch Mar 27 '20 at 01:55
  • @ElliottFrisch I already knew that (object names are just pointers), and that's exactly why the output doesn't make sense. Because if casting doesn't have any impact during execution time then the first line should also be 100, since that's the last time setter method is called. – Jason Mar 27 '20 at 02:04
  • I'll try and explain (again). There are **two** `x`(s). `((SuperClass) f).x = 100;` is `SuperClass.x` and `f.x` is `subclass.x` (that is not legal syntax, but what is **actually** happening). You **can't** override a field. So (to repeat) the two `x`(s) are completely independent, and you **shadow** the name locally. That's it. Consider this `{int x = 2; { int x = 3; }}` - the compiler won't allow that in Java, but that's what you have done with your class. You have two `int x` fields in scope, and one is shadowed. – Elliott Frisch Mar 27 '20 at 02:11

0 Answers0