Having 2 variables with the same name in a class that extends another class in Java
Asked Answered
H

4

19

Following is a part of my code for a project:

public class Body extends Point{
    public double x, y, mass;

    public Body() {
        x = y = mass = 0;
    }

    public Body(double x, double y, double mass) {
        this.mass = mass;
        this.x = x;
        this.y = y;
    }
}

public class Point {
    public double x;
    public double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

I quickly realized that doing this will create two variables inside the Body class called x and two other variables in Body called y. How is this even possible, and why on earth does Java even allow it?

I assume this is the correct code of class Body:

public class Body extends Point{
    public double mass;

    public Body() {
        super();
        mass = 0;
    }

    public Body(double x, double y, double mass) {
        super(x,y);
        this.mass = mass;
    }
}

Thanks for your time

Humphrey answered 21/4, 2009 at 13:46 Comment(1)
So if I have a method with a Point parameter, and I send in an instance of class Body, I will be able to access the x and y variables from Point of that instance? And if I had the input parameter be of type Body instead of Point, I would only be able to access the x and y variables from Body?Humphrey
D
18

In a sense, you are overriding fields of the super class. But it's far easier to do accidentally because there is no overloading of fields (you only have one variable of a given name, the type doesn't matter). This is referred to as variable 'hiding' or 'shadowing'. So, you're correct, you'll end up with two fields with the same name.

Your second example is correct. They are inherited from the super-class and since they are not declared private, they are visible to the subclass. It's generally bad practice to refer directly to a super-class's fields, and unless there is good reason, they should declared private. Your example of invoking the super constructor is the best approach.

Also, if you hide a field with another of the same name, you can still refer to them as super.x, super.y, vs. this.x, this.y, you should avoid this situation if at all possible.

Dosimeter answered 21/4, 2009 at 13:49 Comment(2)
So if I have a method with a Point parameter, and I send in an instance of class Body, I will be able to access the x and y variables from Point of that instance? And if I had the input parameter be of type Body instead of Point, I would only be able to access the x and y variables from Body?Humphrey
@Martin Andersson yes, since Point only 'knows' about x any y, and you're parameter type determines how your code 'sees' the oject. You could of course downcast Point p; Body b = ((Body) p); b.mass = xxx; But never do this! ;-)Dosimeter
D
7

Yes, you'll have two variables, with one hiding the other. It makes sense to allow it for two reasons:

  1. Suppose you've got a base class Base and a derived class Derived which the author of Base has no idea about. Should the author of Base never be able to add any fields, just because a derived class might share the fields? Or should Derived stop compiling when the change to Base doesn't actually affect the correctness?
  2. Your fields should almost always be private, at which point it doesn't matter whether the names are duplicated or not - neither "side" will know about the variables of the other.
Dix answered 21/4, 2009 at 13:52 Comment(1)
1. in my beginner opinion it was much clear when "Derived" stop compile because "Base" already use the same identifier but I think there are more profundity reasons to allow that, who know...Eatmon
D
4

Further to what others have said: Is Body a Point? No, Body has a position property of type Point. So Body probably should not extend Point. If you get rid of inheritance (of implementation) then you get rid of a lot of problems. That and use private (not protected!) and final liberally.

Dayflower answered 21/4, 2009 at 13:57 Comment(1)
While in general "prefer composition over inheritance" is good, it's also possible that the designer wants Body to have all the properties of Point (presumably there are others that have been omitted for clarity).Culch
P
1

I quickly realized that doing this will create two variables inside the Body class called x and two other variables in Body called y. How is this even possible, and why on earth does Java even allow it?

Actually no, you are not creating two variables with the same name, obviously a compiler should not and would not allow this.

What you are doing is shadowing the existing variables defined as x and y, meaning that Body.x and Body.y are essentially overlapping the names for Point.x and Point.y, making the latter two variable completely inaccessible from the Body class (link to Java Language Specification definition of "shadowing").

Name shadowing is generally perceiving as a bad practice and a cause of bugs, and if you turn up the javac compiler warnings, the compiler will dutifully warn you about this.

Polymorphonuclear answered 21/4, 2009 at 13:51 Comment(5)
Actually, you can still access those variables, by using Point.this.x and Point.this.y in the Body classEntablature
Both variables have the same name. They're just declared in different classes. The names of the variables are just "x" and "y", not "Body.x", "Body.y", "Point.x" and "Point.y". Even the link you gave about shadowing says: "Some declarations may be shadowed in part of their scope by another declaration of the same name [...]" - note the "same name" part.Dix
J.S.: I think M.B. intended that to be descriptive rather than executable code.Dayflower
In other words, I know they're not static, I was just attempting to differentiate between the "x" of the Point class and the "x" of the Body class.Polymorphonuclear
I was addressing the claim that the variables don't have the same name. They do, which is precisely why one shadows the other.Dix

© 2022 - 2024 — McMap. All rights reserved.