【问题标题】:Java Inheritance: How to override instance variables/fields from parent class?Java继承:如何覆盖父类的实例变量/字段?
【发布时间】:2020-08-17 04:16:46
【问题描述】:

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

我有一个父类和一个子类。我想重用 parent 类中的方法。通常,这就像super.methodFromParentClass() 一样简单,您就完成了。 然而,当我这样做时,我想要重用的方法是使用来自Parent类的实例变量数据,即或者更确切地说,我确实想要这种行为。我在子类中有 DIFFERENT 初始化数据,这些数据需要传递到我想要重用的方法中。如果你看一下我想重用的方法(下面只是一个简单的例子,但想法是一样的),我在那里创建了多个对象,这些对象使用它调用的类的实例变量。所以你可以看到为什么当我调用 super.methodIWantToReuse 时它不起作用,因为它会获取父数据并将其传递给对象,即使我真的想要它传递我在子类中初始化的数据。我的真实示例还创建了更多的对象,并且我有更多的实例变量,所以我真的想尽可能地重用这段代码(DRY 原则)。

我该如何解决这个问题?将使用 gettersgetFirstName() 并在 Child 类中覆盖它们,因此当我调用 super.methodIWantToReuse() 时使用 Runtime Polymorphism,将 抓取/使用 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();
}

【问题讨论】:

  • 你的父类实例变量是私有的,所以你不能从子类更新它们。因此,您可以使用参数化方法或为实例变量创建受保护的 setter getter。在您的情况下,变量是最终的,因此您实际上甚至无法更新它们。所以从技术上讲,不可能在父类中使用子类变量。
  • 使用super.VarName
  • @GauravJeswani 我可以删除“private”和“final”修饰符。
  • @AshishKamble 我想使用 CHILD 实例变量,而不是父变量。 super.VarName 只会调用父实例变量?
  • @ennth 我在下面添加了我的答案。您可以查看解决方案。

标签: java oop inheritance overriding


【解决方案1】:

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

【讨论】:

  • 或者我可以在子类中调用super.methodIWantToReuse() 之前重新初始化子类中的变量,例如super.varName = varName,我认为它会获取我想要的子变量。
  • 您声明了最终字段(常量)并且不可能为它们分配新值。主要是我想说:“字段不能被覆盖”。
【解决方案2】:

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

如果您将变量更新为 protected 并删除 static/final 修饰符(正如您在 cmets 中提到的那样)。在从父类调用方法之前,在调用超级方法之前更新变量数据。你可以这样做:

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

父类:

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

方法二:如果你想使用参数化方法使其无状态,你可以这样做:

父类:

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

注意:保持局部变量名称与类级别变量相同不是一个好习惯。但为了便于理解,请保持原样。

【讨论】:

  • 但是如果在此之后调用父类(在子将变量设置为子值之后,即 super.firstName = firstName),那么父类不会使用错误的数据吗?我需要某种“清理”来恢复父数据吗?
  • 是的,它将只有新数据。如果是这样,最好在超类中使用参数化方法。
  • @ennth 也用这种方法更新了答案。
  • 谢谢。调用超级。并且更改 varnames 似乎是不好的做法,特别是如果我的程序中的某些内容在之后调用 PARENT 类,并且它具有错误的值。我想我会在这里使用运行时多态性并覆盖 getter。感谢您的帮助。
【解决方案3】:

如果您的意思是 instance variables 而不是您的示例中所示的 static variables(或 class variables),您可以通过更改访问修饰符并删除 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 的实现。

【讨论】:

  • 我有点想重写必须重新创建对象?然后,我并没有真正重用该方法并且无论如何都要重新编写它(我的真实代码有更多的对象和废话)。我想我可以删除 private/static/final 并重新初始化子类中的 super.VarName= VarName 等变量
猜你喜欢
  • 1970-01-01
  • 2019-03-31
  • 1970-01-01
  • 1970-01-01
  • 2019-12-25
  • 2013-08-16
  • 2020-12-19
  • 1970-01-01
  • 2013-10-27
相关资源
最近更新 更多