Object.toString()如何适用于不同的底层类型?

时间:2013-11-23 02:29:33

标签: java object tostring object-to-string

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

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

Object myIntObj = new Integer(5);

如果我这样做:

System.out.println(myIntObj);

输出为:5

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

System.out.println(myIntObj);

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

像:

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

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

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

我希望你理解我的意思。

5 个答案:

答案 0 :(得分:3)

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

这包括toString()

因此,当您实例化new Player()时,您仍然只能访问Object中的方法,但如果您覆盖此方法(如Integer.toString()那样),您仍然会按照定义的方式输出在实例化的类中。

PS:父亲 - >父

答案 1 :(得分:3)

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

  

所以为什么在之前的例子中我没有直接看到引用   数字?通过逻辑,多态的规则说:如果你   在“父”变量中有一个“子”对象,这个对象在里面,   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。

回到你的例子,Integer是一个整数。

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

这打印5因为我是一个整数。 Integer类覆盖toString。引用类型(您指向对象的类型)仅确定您可以调用哪些方法,但不能确定调用该方法的哪个父/子类的版本

答案 2 :(得分:2)

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

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

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

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

答案 3 :(得分:1)

Object myIntObj = new Integer(5);

在这里,您要创建一个新的Integer实例,而不是一个裸Object实例。您将其分配给Object引用的事实不会将其转换为裸Object。它仍然是Integer,但您可以将其引用为Object,因为它会扩展Object。因此,当您致电myIntObj.toString()时,您正在调用该实例的toString()方法。该实例结果是Integer实例。所以Integer.toString()被称为。{/ p>


Object currentPlayer = new Player();

在这种情况下,调用currentPlayer.toString()时适用相同的规则:您实际上正在调用Player.toString()。如果Player类未覆盖toString(),则调用第一个升序父类toString()实现。如果Player直接延伸Object,则会调用Object.toString(),但如果例如Player extends HumanHuman extends Object,则会调用Human.toString()如果它存在如果没有,那么Object.toString()

答案 4 :(得分:0)

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

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

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

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

通常,您将获得与变量在运行时引用的对象关联的行为。此行为通常称为虚方法调用。

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