简体   繁体   中英

Java Inheritance: How to override instance variables/fields from parent class?

Update : I can change the variables from being private, static, or final.

I have a parent class and a child class. I want to re-use a method in the parent class. Normally, this is as easy as super.methodFromParentClass() and you're done. However , when I do this, the method I want to re-use is using instance variable data from the Parent class, which is wrong or rather, I do not want this behavior. I have DIFFERENT initialized data in the child class that needs to get passed into the method I want to reuse. If you look at the method I want to re-use (below is just an example to make it simple, but the idea is the same), I am creating multiple objects in there that use the instance variables of the class its called in. So you can see why when I call super.methodIWantToReuse it won't work, because it will take the Parent data and pass it into the objects, even though I really want it to pass the data I initialize in the child class. My real example is also creating way more objects and I have way more instance variables, so I really want to re-use this code (DRY principle) if at all possible.

How can I get around this? Would using getters ie getFirstName() and overriding them in the Child class, thus using Runtime Polymorphism when I call super.methodIWantToReuse() , would grab/use the Child class instance variable data be the only way???

public class ParentClass {
   private static final String firstName = "Billy Ray";
   private static final String lastName = "Cyrus";
   private static final int age = 58;
   private static final String city = "Hunstville";

public boolean methodIWantToReuse() {
   Object1 obj1 = new Object(firstName, lastName);
   
   Object2 obj2 = new Object(age,city);

   Object3 obj3 = new Object(obj1, obj2);

   Object4 obj4 = new Object(obj3);

   // Passing in the objects created above as argument, which have the Parent instance variable data
   return someRandomMethodHere(obj4);
}
public class ChildClass {
    private static final String firstName = "Miley";
    private static final String lastName = "Cyrus";
    private static final int age = 27;
    private static final String city = "Los Angeles";

public boolean methodIWantToReuse() {
   // DOESN'T WORK CORRECTLY, because ends up using the instance variable data of PARENT class, but it 
   // needs to use CHILD class instance variable data

   super.methodIWantToReuse();
}

You can not override fields of a class. Only methods can be overridden. In your case you have to use getters and override them in sub class.

Your parent class instance variables are Private to that, so you can't update them from Child class. So rather you use parameterize method or create Protected setter/getter for instance variables (or protected variable itself). In you your case the variables are final so you actually can't even update them. So technically that's not possible to use child class variables in parent class.

If you update your variable to protected and remove static/final modifiers (as you mentioned in comments that you can). Before calling method from parent class, update variable data before calling super method. You can do it as below:

Approach 1: Updating data in parent class before calling parent class method.

Parent Class:

public class ParentClass {

    protected String firstName = "Billy Ray";
    protected String lastName = "Cyrus";
    protected int age = 58;
    protected String city = "Hunstville";

    public boolean methodIWantToReuse() {
        // Passing in the objects created above as argument, which have the Parent
        // instance variable data
         Object1 obj1 = new Object(firstName, lastName);

         Object2 obj2 = new Object(age,city);

         Object3 obj3 = new Object(obj1, obj2);

         Object4 obj4 = new Object(obj3);
        return someRandomMethodHere(obj4);;
    }
}

Child Class:

public class ChildClass extends ParentClass {
    protected String firstName = "Miley";
    protected String lastName = "Cyrus";
    protected int age = 27;
    protected String city = "Los Angeles";

    public boolean methodIWantToReuse() {
        // Update data in Parent class first

        super.firstName = firstName;
        super.lastName = lastName;
        super.age = age;
        super.city = city;
        return super.methodIWantToReuse();
    }
}

Approach 2: If you want to use parameterized method to make it stateless, you can do it as below:

Parent Class:

public class ParentClass {

    protected String firstName = "Billy Ray";
    protected String lastName = "Cyrus";
    protected int age = 58;
    protected String city = "Hunstville";

    public boolean methodIWantToReuse() {
        
        return methodIWantToReuse(this.firstName, this.lastName, this.age, this.city);
    }

    public boolean methodIWantToReuse(String firstName, String lastName, int age, String city) {
        // Passing in the objects created above as argument, which have the Parent
        // instance variable data
         Object1 obj1 = new Object(firstName, lastName);

         Object2 obj2 = new Object(age,city);

         Object3 obj3 = new Object(obj1, obj2);

         Object4 obj4 = new Object(obj3);
        return someRandomMethodHere(obj4);;
    }
}

Child Class:

public class ChildClass extends ParentClass {
    protected String firstName = "Miley";
    protected String lastName = "Cyrus";
    protected int age = 27;
    protected String city = "Los Angeles";

    public boolean methodIWantToReuse() {
        // Update data in Parent class first
        return super.methodIWantToReuse(this.firstName, this.lastName, this.age, this.city);
    }
}

NOTE: It's not good practice to keep local variables name same as the class level variables. But kept it here same for just understanding.

In case you really mean instance variables instead of your static variables (or class variables ) as shown in your example, you could make them accessible for your subclass by changing the access modifier and removing the final keyword.

If, however, you actually mean static variables , you cannot reassign them in each subclass as they would all share the same static variables defined by the ParentClass , meaning the last loaded class would be the only result you get by calling your ParentClass#methodIWantToReuse .

Best would be to use OOP to your advantage by instantiating new individual objects with the required arguments, and using them.

By this I mean instead of doing this:

public class Example {
  public static class ParentClass {
    protected String name;
    protected int age;
    
    public ParentClass() {
      name = "The parent";
      age = 35;
    }
    
    public String methodIWantToReuse() {
      return name + " is " + age + " years old.";
    }
  }
  
  public static class AChildClass extends ParentClass {
    public AChildClass() {
      name = "Alice";
      age = 13;
    }
  }
  
  public static class AnotherChildClass extends ParentClass {
    public AnotherChildClass() {
      name = "Bob";
      age = 21;
    }
  }
  
  public static void main(String[] args) {
    // Prints "The parent is 35 years old."
    System.out.println(new ParentClass().methodIWantToReuse());
    // Prints "Alice is 13 years old."
    System.out.println(new AChildClass().methodIWantToReuse());
    // Prints "Bob is 21 years old."
    System.out.println(new AnotherChildClass().methodIWantToReuse());
  }
}

Do this:

public class Example {
  public static class ParentClass {
    protected String name;
    protected int age;
    
    // Variables instantiated here to not cause confusion
    public ParentClass() {
      name = "The parent";
      age = 35;
    }
    
    public String methodIWantToReuse() {
      return name + " is " + age + " years old.";
    }
  }
  
  public static class ChildClass extends ParentClass {
    public ChildClass(String name, int age) {
      this.name = name;
      this.age = age;
    }
  }
  
  public static void main(String[] args) {
    // Prints "The parent is 35 years old."
    System.out.println(new ParentClass().methodIWantToReuse());
    // Prints "Alice is 13 years old."
    System.out.println(new ChildClass("Alice", 13).methodIWantToReuse());
    // Prints "Bob is 21 years old."
    System.out.println(new ChildClass("Bob", 21).methodIWantToReuse());
  }
}

This should also be along the lines of the DRY principle, as you want to reuse your code as efficient as possible instead of coding technically the same over and over again.

As you can see, there was no need for me to override ParentClass#methodIWantToReuse or call the ChildClass ' super's implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM