6

我不明白为什么这在java中有效:

如果我在一个对象中有一个 Integer 对象,例如:

Object myIntObj = new Integer(5);

现在如果我这样做:

System.out.println(myIntObj);

输出是:5

我现在 Integer 类有一个 toString 方法的 ovveride 但在这种情况下是不同的(我认为)。对于多态性,如果我在“父变量”中有一个“子对象”,则该对象不会改变其真实类型(在本例中为整数)但是......它(在 Object 变量中)可以只使用对象类,那么为什么如果我写:

System.out.println(myIntObj);

我可以直接看到数字 5 而不是这个对象的引用?因为对象类中的toString方法默认返回的只是对象引用的字符串。

像:

Object currentPlayer = new Player();
System.out.println(currentPlayer);

在这种情况下,输出是 Player 对象的引用,因为在对象类中调用了 toString 方法。

那么为什么在之前的例子中我没有看到参考而是直接看到数字呢?从逻辑上讲,多态性的规则说:如果你在“父亲”变量中有一个“孩子”对象,这个对象,在里面,remanis 相同,但他被用作对象的一个​​实例,所以他可以只使用类对象等等只是对象的方法,所以我没有看到引用而是直接看到数字真的很奇怪。

我希望你明白我的意思。

4

5 回答 5

4

您解释推理的最后一段略有不正确。

那么为什么在之前的示例中我没有看到参考,而是直接看到了数字?从逻辑上讲,多态性的规则说:如果你在“父亲”变量中有一个“孩子”对象,这个对象,在里面,remanis 相同,但他被用作对象的一个​​实例,所以他可以 只使用类对象等等只是对象的方法,所以我没有看到引用而是直接看到数字真的很奇怪。

开头是正确的,但我加粗的部分是您从中得出的错误结论。

您是正确的,使用多态性,对象确实保持它的任何类型,但引用类型(变量的类型)定义了您可以使用它做什么。但是,引用类型并没有描述对象的作用

这就是多态性背后的意图。它是一种抽象,用于定义可以独立于其工作方式来完成的工作。例如,如果您有以下示例:

public class Vehicle {
    public int getWheelCount() {
        return 1;
    }
}

public class Car extends Parent {
    public int getWheelCount() {
        return 4;
    }

    public void blowHorn() {
        System.out.println("Honk honk!");
    }
}

public class Bicycle extends Parent {
    public int getWheelCount() {
        return 2;
    }
}

Car car = new Car();
car.getWheelCount();  // 4
car.blowHorn();  //"Honk honk!"

Vehicle v = new Car();
v.getWheelCount()  // 4
v.blowHorn();  // COMPILE ERROR HERE!  Unknown method

Bicycle b = new Bicycle();
b.getWheelCount();  // 2

Vehicle v = new Bicycle();
v.getWheelCount();  // 2

您可以由此得出结论,当覆盖子类中的方法时,始终会调用子版本。无论您将其称为车辆还是汽车,汽车始终是汽车。但是通过将其称为车辆,您仅限于调用在所有车辆上定义的方法。

将其与示例联系起来,所有Vehicle对象都有一个轮子大小,因此无论是 Vehicle.getWheelCount() 还是 Car.getWheelCount(),getWheelCount() 始终是可调用的。然而, Car.getWheelCount() 是执行的,因为 Car 覆盖了它。

如果引用类型是Vehicle,则不能调用blowHorn(),因为该方法仅在 Car 上可用。

回到您的示例,整数是整数。

Object i = new Integer(5);
i.toString();  // 5

这会打印 5,因为 i 是整数。Integer 类覆盖 toString。引用类型(您引用对象的类型)仅决定您可以调用哪些方法,而不决定调用哪个父/子类的方法版本

于 2013-11-23T02:58:11.363 回答
3

通过将其定义为Object这意味着您将只能访问Object类中定义的方法。

这包括toString().

因此,当您实例化时,new Player()您仍然只能访问 中的方法Object,但是如果您覆盖它(就像这样Integer.toString()做),您仍然会拥有实例化类中定义的输出。

PS:父亲->父母

于 2013-11-23T02:33:34.653 回答
2

这就是覆盖方法的概念的工作原理:一旦继承层次结构中的某个对象提供了一个实现,就会调用这个实现,除非它被继承层次结构更下方的另一个类覆盖。

由于java.lang.Integer提供了 的覆盖toString(),因此调用此覆盖而不是 . 提供的实现java.lang.Object

System.out.println(myIntObj)和之间没有区别System.out.println(myIntObj.toString()),因为println它将在内部调用toString它不知道如何打印的所有对象。

您的Player类行为不同的原因是它没有覆盖toString(). 如果是这样,您将看到打印的结果。但是,如果没有覆盖,java.lang.Object则会调用 提供的默认实现,它会打印一些通用对象信息。

于 2013-11-23T02:36:57.760 回答
1
Object myIntObj = new Integer(5);

在这里,您正在创建一个新Integer实例,而不是一个裸Object实例。您将其分配给Object引用的事实不会将其转换为裸Object. 它仍然是 an Integer,但您可以将其作为 an 引用,Object因为它扩展了Object。因此,当您调用 时myIntObj.toString(),您正在调用该实例的toString()方法。那个实例原来是一个Integer实例。也因此Integer.toString()被称为。


Object currentPlayer = new Player();

在这种情况下,调用时适用相同的规则currentPlayer.toString():您实际上是在调用Player.toString(). 如果Playerclass 没有 override ,则调用toString()第一个升序父类实现。toString()如果Player直接 extends Object, thenObject.toString()会被调用,但是如果例如Player extends Humanand Human extends Object, thenHuman.toString()如果存在则将被调用。如果没有,那么Object.toString()

于 2013-11-23T02:35:18.630 回答
0

考虑这种情况,其中 Employee 有一个子类 Manager,它有一个方法 getDetails() 被覆盖,

Employee e=new Employee();
Employee m=new Manager();

如果您调用 e.getDetails(),您将获得与 Employee 相关的行为。

如果您调用 m.getDetails(),您将获得与 Manager 关联的行为。

通常,您会获得与变量在运行时引用的对象相关联的行为。这种行为通常被称为虚拟方法调用。

因此,当您的引用是一个对象时,您获得与 Integer 关联的行为的原因是因为您在运行时引用了一个 Integer 对象。

于 2013-11-23T02:50:52.470 回答