不同的子类值能否体现在继承的方法中?

Can different subclass values be reflect in inherited methods?

我正在尝试创建一个程序来帮助我学习 Java 的继承。然而,在这个过程中,我发现了我以为自己学到的问题。

程序很简单。我有一个名为 Gun 的超类和一个名为 M1911 的子类。这个程序的想法只是向我展示你不必像我制作的那样重复方法 shoot()。然而,问题就在这里。我想要 shoot() 向控制台打印一条消息说

"GunModel: Pew, pew!"

。 GunModel 和 shoot() 在 Gun 和 M1911 子类中被定义为具有不同于从 Gun 继承的初始值的值。这意味着如果 M1911 有一个 GunModel == "M1911",方法 shoot() 将通过打印

反映出来
"M1911: Pew, pew!"

这一切(显然?)都不起作用,因为在我看来子类内部的值对继承的方法没有影响。那么,如果是真的,为什么会这样。另外,我缺少的继承目标是什么?这似乎不仅仅是避免重复。

编辑:这是我应该先给出的代码。

public class Gun {  
    protected String GunModel;
    public void shoot() {
        System.out.println(GunModel + ": Pew, pew!");
    }
}

public class M1911 extends Gun {
    public String GunModel = "M1911";
}

这是我从你的代码中得到的(来自未格式化的评论):

public class Gun 
{ protected String GunModel; 
  public void shoot() 
  { System.out.println(GunModel + ": Pew, pew!"); 
  } 
} 

public class M1911 extends Gun 
{ 
  public GunModel = "M1911"; 
}

正如 'user' 在评论中指出的那样,"GunModel" 不能被覆盖,所以你这里有两个同名的不同变量。

您可以执行以下操作:

public class Gun 
{ 
  protected String GunModel = "Gun"; 
  public void shoot() 
  { System.out.println(GunModel + ": Pew, pew!"); 
  } 
} 

public class M1911 extends Gun 
{ 
  public M1911()
  {
    GunModel = "M1911";
  }
}

之后,如果有人执行gunVariable = new M1911()gunVariable.shoot(),就会打印"M1911: Pew, pew!".

还有其他方法可以做到这一点——GunModel 可以是私有的,可以通过 getter 和 setter 方法访问,而不是直接访问。

关于 Java 代码的一句话:按照惯例,类 以大写字母开头,变量以小写字母开头。使用这个普遍遵循的约定,您的变量将拼写为 "gunModel" 而不是 "GunModel";这样做的一个好处是很容易分辨哪些是变量,哪些是类。人们可以通过查看它们后面有括号来判断哪些以小写字母开头的东西是方法。

当你继承某些东西时,你可以继承:行为和状态。 状态基本上不能被覆盖,在你的代码片段中,内存中的 M1911 实例实际上有 2 个 "slots" - 一个 GunModel 来自 Gun class 和一个 GunModel 来自 M1911 class.

通常你不会在实际程序中这样做。

另一方面,行为可以被覆盖。我所说的行为是指方法:

class Gun {
    public void shoot() {
        System.out.println("Gun : Pew, pew!");
    }
}

class M1911 extends Gun {
    public void shoot() { // overrides
        System.out.println("M1911 : Pew, pew!");
    }
}

不能通过继承覆盖单个属性(即字段)。有许多语言可以做到这一点,例如 C# 和 Python。 Java,但是,只支持方法的覆盖。有多种方法可以处理此问题:

  1. 创建供应商方法 "getGunModel" returns GunModel 而不引用该字段。
  2. 如果武器的身份仅基于其名称,请创建一个带有字段 final private String gunName 的枚举类 public enum Guns,并在 shoot() 方法中引用该字段。此方法必须在枚举上下文中定义,即不要在枚举中的每个列出的实例中重新定义 shoot(),而是动态调用它:
enum Guns {
    SOMEGUN("M1911"),
    THATGUN("AK-47");

    private final String gunName;

    private Guns(String modelName) {
        this.gunName = modelName;
    }

    public void shoot() {
        System.out.println(this.gunName + ": Pew pew!");
    }
}

// Now we can call Guns.SOMEGUN.shoot(), which will return "M1911: Pew pew!" over stdout

等等