1

I'm new to Java, maybe this is a silly question.

Let's say I have a src.utils package containing the following classes:

public class ClassC {
    public String sC = "I'm C";
}

public class ClassB extends ClassC {
}

public class ClassA {
    public ClassB cB;
    public String sA;

    public void setCB(ClassB cB) {
        this.cB = cB;
        this.sA = cB.sC;
    } 
}

And a src package containing the following classes:

import src.utils.*;
public class NewClassB extends ClassB {
    public String sC = "I'm NewB";
}

public class Application {
    public static void main(String[] args) {
        
        NewClassB ncB = new NewClassB();
        
        ClassA cA = new ClassA();
        cA.setCB(ncB);          // Here I'm passing an object of type NewClassB instead of ClassB
        
        System.out.println(cA.sA);  // Here I get "I'm C" instead of "I'm new B"
    }
}

Important: I don't want to mention or write the NewClassB anywhere in the src.utils package. It's just a class that I developed later.

The problem is: Why am I getting "I'm C" when running the main class? I am passing to ClassA an object of type NewClassB (instead of ClassB), and I have overwritten the sC attribute in the definition of NewClassB. How could I do? I tried with an interface, but then I couldn't instantiate it.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • 3
    "I have overwritten the sC attribute in the definition of NewClassB" - no you haven't, you've declared a *new* field with the same name. Fields don't behave polymorphically: if you'd used a method (`getName` or something similar) and overridden that in `NewClassB`, it would be fine. (This is yet another reason not to use public fields.) – Jon Skeet Apr 17 '21 at 07:47
  • 1
    Side note: your question title refers to passing values into constructors, but you're not doing that... you're passing a value into a method. It would be good to make the question consistent. – Jon Skeet Apr 17 '21 at 07:48
  • Thank you both, now I have learned something new... Btw that wasn't what I actually wanted to ask, I think I'll delete the question – user14520608 Apr 17 '21 at 08:25

1 Answers1

3

NewClassB.sC does not override ClassC.sC. It's a brand new field. When you access cB.sC, you are accessing the sC declared in ClassC, since cB is of type ClassB.

Rather than declaring a brand new field, you can set the field in NewClassB's constructor instead:

class NewClassB extends ClassB {
    public NewClassB() {
        sC = "I'm NewB";
    }
}

However, using public fields is rather a bad idea - they offer no encapsulation. I suggest that you encapsulate this a bit more. All ClassA needs to know is to be able to get a string from ClassB, so you should only expose a getter in ClassC:

private String sC = "I'm C";
public String getSC() {
    return sC; // or even return "I'm C" directly if this is a constant
}

In ClassA, call this getter rather than directly accessing the field:

this.sA = cB.getSC();

In NewClassB, you can then override this getter to return something different:

// even though this field does not override ClassC's sC, that's fine, 
// because ClassA depends on getSC only, which does override ClassC.getSC
private String sC = "I'm NewB";

@Override
public String getSC() {
    return sC; // or even return "I'm NewB" directly if this is a constant
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Thank you, that was very helpful. Actually my problem was: i have ```ClassA``` and ```ClassB``` in ```pkg1```, how to tell ```ClassA``` to use a subclass ```NewClassB``` belonging to ```pkg2``` instead of ```ClassB```? I think I put the wrong question, then I'm probably going to delete it... – user14520608 Apr 17 '21 at 08:12
  • @user14520608 The code in `ClassA` and `Application` looks fine to me. What problem are you having exactly? – Sweeper Apr 17 '21 at 08:17
  • 1
    @user14520608 It seems like you have got rid of too much context when asking the question, so much so that the answer doesn't apply to the original problem anymore. Try asking a new question, in the context of XML parsing and error handlers, and remember to show a [mcve]. – Sweeper Apr 17 '21 at 08:25