4

I have a Super class and a bunch of subclasses. I want to have one field that has the same name in every single subclass, but I do not want it to be defined in the super class, or at least I do not want to use that value. This is what I have right now

public abstract class Big {

    public String tellMe = "BIG";

    public Big() {}

    public void theMethod() {
        System.out.println ("Big was here: " + tellMe() + ", " + tellMe);
    }
    public String tellMe() {
        return tellMe;
    }
}

public class Little extends Big{

    public String tellMe = "little";
    public Little(){}

    public String tellMe() {
        return "told you";
    }
    public static void main(String [] args) {
        Little l = new Little();
        l.theMethod();
    }
}

When I run Little, this is the output

Big was here: told you, BIG

I am not sure why 'told you' is printed out while tellMe refers to "BIG". How can both be true?

My problem is that I want the method tellMe() to be in Big, and to have the variable tellMe (that it will actually return) to be defined in all the subclasses. The only way I can get this to work is as I have written, by rewriting the tellMe() method in each subclass. But doesn't that defeat the whole purpose of inheritance??? Please help

EDIT: I do not use the constructor in my subclasses. All I want is a field that can be set in all subclasses and a method in the super that uses those values. I don't understand why this isn't possible because every subclass would have to implement it, so it would make sense... If this simply is not possible, let me know please

2
  • The method tellMe() and the field tellMe have absolutely no correlation, regardless of name. Commented Jul 31, 2012 at 16:41
  • i know... I don;t udnerstand the purpose of this comment but thanks Commented Jul 31, 2012 at 17:30

6 Answers 6

6

Fields are not virtual, unlike methods. For this reason, it is a bad idea to declare fields with the same name as a field in another class in the hierarchy. The field referred to in theMethod is always going to be from Big (i.e. when you declare a field with the same name, it just hides the old field when in the scope of the replacing class, but doesn't replace it).

One solution would be to override a method that gets the field from the current class:

In theMethod replace the tellMe field with getTellMe() and for all classes override getTellMe() to return the correct value (or the field that hides the superclass's field).

Sign up to request clarification or add additional context in comments.

9 Comments

this is my problem. Why would it EVER be necessary to create the same exact method hundreds of times in my subclasses when the PURPOSE of inheritance is to condense code... why is there no such thing as an abstract field that I vcould have in Big and define in all of my littles?
getTellMe(){return "Text";} isn't much longer than tellMe="Text";. It's just the design of the JVM: fields are not virtual. Declaring and hiding a bunch of fields is definitely worse: memory is allocated for each instance for each field. See Keith Randall's solution - he changes the field rather than declares new ones.
I do not use a constructor in my subclasses. I would also like to be able to directly edit this field... so I would have make a field, and then make a get and a set. IN EVERY SUBCLASS... i do not understand why this is necessary for the reason I posted above. It becomes significantly longer than just making one field
Well, his solution is a little longer than. You'll probably need to add more information to your question; there is only so much we can assume about what you are actually trying to accomplish. If the value of the field is the only difference, than I suggest setting the field from the user of the class.
what do you mean by "setting the field from the user of the class."
|
2

You can overwrite the value of Big.tellMe in the constructor of Little.

get rid of:

public String tellMe = "little";

and change the Little constructor to:

public Little(){
    tellMe = "little";
}

at that point, you can get rid of Little.tellMe() also.

5 Comments

+1. I like public fields to be final, but this is a good solution, if you trust the programmer.
no, it is not a good solution. Why would I have to put the exact smae line in hundreds of subclasses when the entire purpose of inheritance is to condense code? I also do not even use a constructor so this does not help me
Huh? This solution requires less code than your solution of declaring and hiding fields.
@ColeCanning: You only have to add one line to each subclass. I don't see how you're going to do any better than that.
I do not use a constructor in my subclasses, at all. Also I know the code I provided is wasteful and nonsensical, that is why I am here. I had to provide the way I found to be closest to what I needed
2

What you are doing is hiding the super class field, not overriding it, as the Java documentation states. And it's also stated that it's not a good idea to do it.

So, the dynamic lookup won't work as for a method. If the variable is read from the son class, it will take "its" field value. On the top class, the other one.

What you can override in Java is the behaviour, so what I would suggest is to define a method

public String tellMe() {
  return "Whatever";
}

that you can override in the subclasses to return whatever string you need.

Comments

1

Instead of defining tellMe inside of Big (since you said you do not want to define/use that value in Big) you can create a function in Big:

public abstract String tellMeString();

And define that in each subclass like so (for Little):

public String tellMeString()
{
    return "Little";
}

Then theMethod can execute:

System.out.println ("Big was here: " + tellMe() + ", " + tellMeString());

In this case you wouldn't have to define a variable "tellMe" at all, you just override tellMeString in each subclass to return different Strings.

5 Comments

"And define that in each subclass like so (for Little):" this is literally what I did, and what I have a problem with. Why would I make the same method in every single subclass when the point of inheritance is condensing code?
Here the idea is that the method executes differently depending on the subclass. You want every subclass to provide a different value for the same function, and inheritance offers a solution by allowing each subclass to provide its own implementation.
yes i want every subclass to provide a different value for THE SAME FUNCTION... why would i have each subclass offer its own, identically written, subclass?
The function is declared in the super class, and it is up to the subclass(es) to define it. A super class is not aware of the details of any classes that inherit from it. For example, I could take your code, create my own subclass of Big, and do whatever I want. How is your superclass to know what my subclass contains? How can you program all the possibilities? Also by using methods to access data, it is much easier to refactor code in the future, as there is a well defined point of entry into the class, and this point of entry (the function) can be changed and maintain the same signature.
"How is your superclass to know what my subclass contains?" This is exactly what an abstract field would allow me to do. I don't know why they don't exist... oh well. This would also make it significantly easier to refactor as there would only be ONE method in the super class, and all the subclasses would have ONE variable, as opposed to identical method signatures that I would have to go through and make the same change to
1

Fields are not inherited as you are expected. You can access the super class' field (unless it is private) from subclass. But you cannot "override" field. This is why tellMe used by method implemented in super class Big uses variable defined in the same class.

If you want inheritance use methods. For example you can implement method "tellMe()" that returns "BIG" in super class and "little" in subclass:

class Big {
    protected String tellMe() {
        return "BIG";
    }
}
class Little {
    @Override
    protected String tellMe() {
        return "Little";
    }
}

Alternatively you can initialize variable tellMe in constructor:

class Big {
    private String tellMe;
    public Big() {
        this("BIG");
    }
    protected Big(String tellMe) {
        this.tellMe = tellMe;
    }
    protected String tellMe() {
        return "BIG";
    }
}
class Little {
    public Little() {
         super("Little");
    }
}

Now new Little().tellMe() will return "Little": the variable in super class was initialized when constructing the object; the method defined in super class returned this variable.

1 Comment

Thanks for the answer. I still do not understand why fields cannot be declared abstractly, it makes so much sense to me
1

Methods can be overridden, fields are visible at the scope where they're called.

static class Big {
    String field = "BIG";
    String bark()   { return "(big bark)"; }

    void doIt() {
        System.out.format("field(%s) bark(%s)\n", field,bark());
    }
    void doIt2()    {
        System.out.format("2:field(%s) bark(%s)\n", field,bark());
    }
}

static class Small extends Big {
    String field = "small";
    String bark()   { return "(small bark)"; }
    void doIt2()    {
        System.out.format("2:field(%s) bark(%s)\n", field,bark());
    }
}

public static void main(String... args) {

    Big b = new Big();
    b.doIt();
    b.doIt2();

    Small s = new Small();
    s.doIt();
    s.doIt2();
}

Output is:

field(BIG) bark((big bark))
2:field(BIG) bark((big bark))
field(BIG) bark((small bark))
2:field(small) bark((small bark))

since doIt() is defined in the Big class, it will always see the Big version of field. doIt2() is defined in Big, but overridden in Small. The Big.doIt2() sees the Big version of field, the Small.doIt2() version sees the Small version of field.

As others have pointed out, it's a pretty bad idea to do this - a better approach is to set the new value in the subclass constructor, or to use a method which is overridden.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.