Java继承:如何从父类覆盖实例变量/字段?

时间:2020-08-17 04:16:46

标签: java oop inheritance overriding

更新:我可以将变量更改为私有,静态或最终变量。

我有一个父班和一个子班。我想重用 父级类中的方法。通常,这就像super.methodFromParentClass()一样简单,您已完成。 但是,当我这样做时,我想重用的方法是使用来自父类的实例变量数据>错误,或更确切地说,我 想要这种行为。我在子类中有 DIFFERENT 初始化数据,这些数据需要传递到要重用的方法中。如果您查看我想重用的方法(下面只是一个简单的示例,但是想法是相同的),那么我将在其中创建多个对象,这些对象使用其调用的类的实例变量。因此,您可以了解为什么我调用super.methodIWantToReuse时不起作用,因为它将获取父数据并将其传递到对象中,即使我 我真的希望它传递我在子类中初始化的数据。我的实际示例还在创建更多的对象,在实例中创建了更多的实例变量,因此我真的想尽可能地重用此代码(DRY原理)。

我该如何解决?将使用 getters getFirstName()并将其覆盖到Child类中,因此在我调用super.methodIWantToReuse()时使用运行时多态性将会 grab /使用 Child类实例变量数据是唯一的方法?

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();
}

3 个答案:

答案 0 :(得分:3)

您不能覆盖类的字段。只有方法可以被覆盖。在您的情况下,您必须使用getter并在子类中覆盖它们。

答案 1 :(得分:2)

您的父类实例变量对此是私有的,因此您不能从Child类更新它们。因此,您宁可使用parameterize方法或为实例变量(或受保护变量本身)创建Protected setter / getter。在您的情况下,变量是最终变量,因此实际上您甚至无法更新它们。因此从技术上讲,不可能在父类中使用子类变量。

如果将变量更新为protected并删除static/final修饰符(如您在注释中所提到的)。从父类调用方法之前,请在调用超级方法之前更新变量数据。您可以按照以下步骤进行操作:

方法1::在调用父类方法之前更新父类中的数据。

父级:

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);;
    }
}

儿童班:

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();
    }
}

方法2:如果要使用参数化方法使其变为无状态,则可以按以下步骤进行操作:

父级:

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);;
    }
}

儿童班:

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);
    }
}

注意:保持局部变量名称与类级别变量相同不是一种好习惯。但是为了理解起见,在这里保持相同。

答案 2 :(得分:0)

如果您的意思确实是instance variables而不是示例中显示的static variables(或class variables),则可以通过更改access修饰符并删除来使它们可用于子类。 final关键字。

但是,如果您实际上是指static variables,则不能在每个子类中重新分配它们,因为它们都将共享由ParentClass定义的相同静态变量,这意味着最后一个加载的类将是唯一的通过调用ParentClass#methodIWantToReuse得到的结果。

最好是通过实例化带有所需参数的新单个对象并使用它们来利用OOP的优势。

这是我的意思,而不是这样做:

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());
  }
}

执行此操作:

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());
  }
}

这也应该遵循DRY原则,因为您想尽可能高效地重用代码,而不是一遍又一遍地进行技术上的重复编码。

如您所见,我不需要重写ParentClass#methodIWantToReuse或调用ChildClass的super的实现。