创建子类的两种方法几乎相同?

时间:2019-09-20 16:29:35

标签: java inheritance

我是Java新手。我创建了一个超类和一个从其扩展的子类:

class Car {
    private String name;
    private int wheels;

    public Car(String name, int wheels) {
        this.name = name;
        this.wheels = wheels;
    }
}

class Ford extends Car {
    public Ford(String name, int wheels) {
        super(name, wheels);
    }

}

然后在main方法中,我可以创建一个超类和一个子类的实例:

  Car car = new Car("car", 4);

   Ford ford = new Ford("ford", 6);

   Car ford2 = new Ford("ford", 6);

我只是想问一下,以福特开头或句子开头是Car的实例是否有区别?如您所见,福特和福特2创建不同。请注意,我知道ford和ford2是不一样的,因为它们是具有不同指针的引用变量。我只是想知道创建它们的语法。 谢谢

编辑:

我发现了差异,但不了解其背后的逻辑。

  • 如果Car类中有一个方法,则可以从福特和福特2中调用它。
  • 如果在Car和Ford类中具有相同名称的方法,则可以从ford和ford2两者中调用它,它将在子类中调用该方法
  • 如果您仅在Ford类中有一个方法,则无法从ford2调用它-您会收到错误消息。

我不太明白为什么,福特2仍然是福特的一个实例

5 个答案:

答案 0 :(得分:2)

到目前为止,我真的不喜欢这些答案。他们使简单的声音变得复杂。

变量只是参考的持有人。

从示例中可以看到,变量的类型不必与它所保存的引用的确切类型匹配。变量必须比其引用等于或更通用(或者,如果您愿意,等于或更不具体)。 CarFord更笼统,因此分配是可以的。

每个引用都可以由Object变量保存,因为这是Java中最通用的类型。

Object foo = new Car(1, 6);
Object bar = "hello world";

现在,使用这些变量的困难在于我们只能从Object类中调用方法。通过将变量声明为Object,当我尝试访问内容时,无论那里实际存储了什么,我都只能使用Object中的方法。

Object中有几种方法(例如toString),所以也许可以,但是在大多数情况下,分配给Object并不是很有用。

因此,我们对变量的定义越具体,就越有可能获得更多的功能。

当你说

Car car = new Ford("ford", 6);

可能存在某些特定于Ford的功能,当从此变量引用它时,我们将无法访问。我们总是可以稍后通过投射实例来解决该问题,但是除非绝对必要,否则您应该避免这样做。

但是,我们越通用,我们的代码就越灵活。如果一个方法仅将福特汽车作为参数,那将有很大的局限性。如果可以将任何汽车作为参数,那么它会更加灵活。

通常,当为变量选择正确的类型时,您可以从脑海中开始,尽可能使用最通用的类​​型,然后使其更加具体,直到适合您的用例为止。

例如,如果您随后可以更喜欢Iterable而不是Collection,而不喜欢Collection而不是List,并且喜欢List而不是{{1 }}。

答案 1 :(得分:1)

   Ford ford = new Ford("ford", 6);

   Car ford2 = new Ford("ford", 6);

两个对象变量都引用福特类对象。但是对象变量的类型不同。就像福特是福特的类型,而福特2是汽车的类型。

它称为通用对象创建。普遍建议创建对象引用,因为您可以通过分配继承同一父类的不同子类来更改对象引用类型。

除了以下提到的区别外,这种情况也是有用的。

Car car = new Car("car", 4);

此car对象只能访问Car类方法。

Ford ford = new Ford("ford", 6);

此对象可以访问两个类的所有方法。但是,假设您在两个类中都具有如下所示的1种方法

   public static void a(){
        system.out.println("static method");
   }

如果福特对象调用方法a()。它将运行子类中存在的方法。因为福特变量是福特子类的类型。

 Car ford2 = new Ford("ford", 6);

此对象可以访问两个类的所有方法。但是,假设您在两个类中都具有如下所示的1种方法

   public static void a(){
        system.out.println("static method");
   }

如果福特对象调用方法a()。它将运行超类中存在的方法。因为ford2变量是福特超类的类型。

答案 2 :(得分:0)

您可以在Ford上调用任何ford方法。

您可以在Car上调用任何ford2方法。

答案 3 :(得分:0)

从技术上讲,它们并不相同-==将给出false-但它们持有相同的数据(不相同意味着修改一个不会影响另一个),并且它们是相同的类型。但是,您只能通过将ford2类(如果有的话)中的类型强制转换为Ford(在此状态下,位于{{1 }}只能调用Ford的方法。

答案 4 :(得分:0)

  

我只想问实例之间是否有区别   福特和福特2?还是完全一样?

最佳答案是:这取决于

这完全取决于您所说的“相同”。

在Java中,new运算符是创建新对象所必需的。因此,这两个分配会将新创建的对象分配给变量fordford2。这些对象将具有不同的引用,因此在JVM中具有不同的标识。结果,以下内容将得出false

boolean b = (ford == ford2);

但是,可以说这两个对象具有相同的属性,因为它们的实例字段包含相同的值。就目前而言,该表达式也将得出false

boolean b = (ford.equals(ford2));

因为两种类型的已分配变量(即equals()Object)都从Car继承的默认Ford方法执行了与评估时相同的引用比较在之前的声明中。如果equals()类中的Ford方法被重写以执行值比较(而不是默认的引用比较),如下所示:

@Override boolean equals(Object ob) {
    if (!(ob instanceof Ford)) return false;
    Ford f = (Ford) ob;
    return this.name.equals(f.name) && this.wheels == f.wheels;
}

然后下面的表达式将得出true

boolean b = ford.equals(ford2);

TL; DR:由变量fordford2引用的对象具有相同的类型(即它们都是Ford),相同的属性但具有不同的标识。如果如图所示为类Ford定义了一个值比较,则它们将具有相同的值,否则就没有。

相关问题