动态(运行时)多态性在java中是如何工作的?换句话说,JVM如何知道要调用哪些方法



假设您有一个对象ArrayList<Object> arr = new ArrayList<Object>();的arrayList,然后用几个不同的对象填充这个arrayList,所有这些对象都继承自object

arr.add(new Integer(1));
arr.add("Im a String");
arr.add(new SomeOtherObject);

假设您随后循环通过调用.toString()方法的arrayList,这实际上会按预期工作,调用StringInteger类的重写toString()方法,让我困惑的是,对JVM来说,arrayList中的IntegerString对象被隐式地转换为对象,那么JVM究竟是怎么知道将它们重新划分为它们被放入arrayList之前的样子的呢?很抱歉,如果这个问题有一个明显的答案,但这似乎对我来说没有多大意义

每个对象的类型都存储在该对象的头中。当您将引用强制转换为对象时,这不会以任何方式更改对象。

例如,当您调用.toString时,它会从类的描述中查找要调用的方法。注意:如果它可以优化代码,就不必每次都这样做。

假设您有一个Fooclass和一个名为arrArrayList<Object>。当您说arr.add(new Foo())时,Foo的新对象class将作为新元素添加到arr中。这是可能的,因为Fooclass并且是从Object继承的。然而,对象是Foo,即使Foo是从Object继承的。因此,当您调用它的toString时,它将调用您创建的Foo对象的toString

假设您有一个Birds和Eagles的fly的数组列表。所以,如果你调用Birdfly()方法,它实际上是Eagle,它会飞得很漂亮。事实上,这是继承的一个伟大特征,非常有意义。

事实是,JVM不知道如何将它们转换回原来的版本。我们必须为此完成任务。考虑一下。。。(在你的代码行之后)

SomeOtherObject obj = arr.get(2); //trying to access the third element

你肯定会得到编译时的错误。OK,现在尝试显式强制转换返回的对象。

SomeOtherObject obj = (SomeOtherObject)arr.get(2);

它非常好用!为什么?因为从get()方法返回的对象与要强制转换的类型兼容。

现在也考虑一下(我知道我做不到),只是为了检查JVM是否可以告诉我们哪个对象是什么。

SomeOtherObject obj = (SomeOtherObject)arr.get(1); //1 instead of 2

是的,是的,我知道这个数组的第二个成员是String,我不能这样做。但让我们看看JVM有什么要说的(尽管并没有编译器错误)。我们得到的消息是,无法将对象强制转换为指定的类型。(但我们没有得到物体的确切类型)。

你明白了吗?这里的JVM只知道传递给这个数组的对象只是与Object兼容的对象。它不知道我们是否真的传递了String、int(或者更确切地说是Integer,因为基元不能存储在集合中)或SomeOtherObject(Java中定义的任何类都是Object的直接子类)。

现在回答您的问题:

  1. (我如何才能让String和Integer恢复正常(尽管我仍然需要对它们进行类型转换))原因是String和包装类(Integer是一个包装类)已经重写了从Object继承的toString()方法。因此,打印这些对象会得到实际值。

  2. (JVM如何知道要将它们转换为哪种类型)JVM实际上并不知道在返回给用户之前要将哪个对象转换为哪一种类型。它只会返回Object的一个实例(JVM都知道这个对象)。我们必须将其显式转换为适当的类型。

希望我回答了你的问题。如果不清楚,请告诉我。

关于运行时多态性(您的标题问题)的详细描述如下:http://www.javatpoint.com/runtime-polymorphism-in-java

最新更新