user483315
user483315

Reputation: 83

Java inheritance

So I've been trying to find the proper way to get what should be pretty straightforward inheritance to function (the way I want ;)) and I'm failing miserably. Consider this:

class Parent
{
  public String name = "Parent";

  public Parent() {};
  public void doStuff()
  {
     System.out.println(name);
  }
}

class Child extends Parent
{
  public String name = "Child";
  public Child()
  {
    doStuff();
  }
}

I understand that Java doesn't do what I'd expect in this case as for some reason member variables aren't overridden the same way methods are but my question is what is the proper way to achieve the behavior I'd expect? I'd like my base class to contain some functions that operate on member variables provided/defined by a given subclass. I'd think get/sets could work, but then it destroys my ability to just call super() and have my base class do the construction needed making my subclasses contain a bunch of construction instead of isolating it to the base class.

Any constructive suggestions are welcome.

Upvotes: 6

Views: 9206

Answers (6)

Shovan Kumar Paul
Shovan Kumar Paul

Reputation: 11

You don't need to redefine your member variable in the subclass. You can write your code as @Stephen C says

class Child extends Parent {
    public Child() {
        name = "Child";
        doStuff();
    }
}

In your post

I'd like my base class to contain some functions that operate on member variables provided/defined by a given subclass.

You will write your super class at first and at this stage your super class does not know about your subclass.

Upvotes: -1

Nikita Rybak
Nikita Rybak

Reputation: 67986

You can always replace a variable with getter, if you want such kind of 'variable-inheritance'. Not sure if 'variable-inheritance' ((c)) is a good design pattern in general, though.

class Parent {
    public void doStuff() {
        System.out.println(getName());
    }

    public String getName() {
        return "Parent";
    }
}

class Child extends Parent {
    public Child() {
        doStuff();
    }

    public String getName() {
        return "Child";
    }
}

Or you could have protected constructor in Parent class, taking the name to use.

edit
I wouldn't call it a 'hack'. And version with passing parameter into parent constructor can be pretty elegant too.

class Parent {
    private final String name;

    // don't let use to invoke this constructor, only for child classes
    protected Parent(String name) {
        this.name = name;
    }

    // public constructor for users
    public Parent() {
        this("Parent");
    }

    public void doStuff() {
        System.out.println(name);
    }
}

class Child extends Parent {
    public Child() {
        super("Child");
        doStuff();
    }
}

do you have any idea why Java seems to have abandoned the concept of inheriting member variables?
Java has abandoned a lot of C++ concepts (starting from infamous multiple inheritance), because they didn't add that much value to the language, but increased its complexity.
Although I don't have anything against variable-inheritance, I'm not suffering without this concept either. And personally, I like the language simple and clean.

Upvotes: 9

Stephen C
Stephen C

Reputation: 718688

What you are trying to do won't work in Java. In Java, attributes declared in a parent class are not overridden in a child class.

If you want polymorphic behavior, then you need to declare the attributes private, and declare corresponding getter methods in the parent class that you can override in the child class.

Alternatively:

class Child extends Parent {
    public Child() {
        name = "Child";
        doStuff();
    }
}

though @shoebox639's answer does this in a more elegant way that allows you to declare the attribute as final. (Mutable public attributes are not a good idea ...)

Upvotes: 1

shoebox639
shoebox639

Reputation: 2312

You are correct in that you can't override members of the class. You can achieve this by making name protected and setting it in the constructor.

class Parent {   
    protected string name;

    public Parent() { name = "parent"};   
    public doStuff() {
        System.out.println(name);   
    }
}

class Child extends Parent {   
    public Child() {
        name = "child";
        doStuff();
    }
}

Upvotes: 2

L. Cornelius Dol
L. Cornelius Dol

Reputation: 64026

The subclass variable name is shadowing the super classes variable of the same name. So when Child declares and assigns name it's another separate variable.

Instead, consider name to be a property of the parent inherited by the child and pass name as an argument to the Parent constructor. Then you would invoke super("Child") from the child constructor.

Also, as a public property, it should be final. Otherwise expose it via getters and setters.

Upvotes: 3

Jon Skeet
Jon Skeet

Reputation: 1499790

Do you really need two different name variables for a single instance? Do you genuinely have the idea of an object having a "name-when-viewed-as-Parent" and a "name-when-viewed-as-Child"? If not, just have a single variable in the Parent class.

How would the Parent class know which variables are going to be provided by the child? If every subclass is going to have the same set of variables, why aren't they in the parent class?

If you could give a more concrete example of the problem you're trying to solve, it would make it easier to give a concrete answer.

Upvotes: 7

Related Questions