2016-01-13 53 views
0

所以我在这里写了一个简单的java代码,如下所示。如何上传对象存储在爪哇的堆

package com.example.aakash; 

public abstract class Book { 
    String title; 
    String author; 

    Book(String t,String a){ 
     title=t; 
     author=a; 
    } 

    abstract void display(); 
} 

所以Book是一个抽象类,它被两个不同的类MyBook和ABook类扩展,如下所示。

package com.example.aakash; 

public class MyBook extends Book { 
    private int price; 

    MyBook(String t, String a,int p) { 
     super(t, a); 
     price = p; 
    } 

    @Override 
    public void display(){ 
     System.out.println("Title: "+title); 
     System.out.println("Author: "+author); 
     System.out.println("Price: "+price); 
    } 
} 

package com.example.aakash; 

public class ABook extends Book { 
    private int price; 

    ABook(String t, String a,int p) { 
     super(t, a); 
     price = p; 
    } 

    @Override 
    public void display(){ 
     System.out.println("Title: "+title); 
     System.out.println("Author: "+author); 
     System.out.println("Price: "+price); 
    } 
} 

package com.example.aakash; 

import java.util.ArrayList; 

public class Main { 
    public static void main(String[] args){ 
     ArrayList<Book> myArray = new ArrayList<Book>(); 
     String bookName = "Book"; 

     for(int i=1;i<=10;i++){ 
      if(i%2==0){ 
       String tempBook = bookName + i; 
       String author = "Author2"; 
       Book temp = new MyBook(tempBook,author,i*50); 
       myArray.add(temp); 
      }else{ 
       String tempBook = bookName + i; 
       String author = "Author1"; 
       Book temp = new ABook(tempBook,author,i*50); 
       myArray.add(temp); 
      } 
     } 

     for(int i=0;i<10;i++){ 
      Book temp = myArray.get(i); 
      temp.display(); 
      System.out.println("--------------------------------------------------"); 
     } 
     myArray.get(5).display(); 
    } 
} 

好的,所以当我运行这个程序时,显示方法每次都打印正确的书,作者和价格。只是他们存储的方式。但是,在运行时,JVM不知道数组列表中的Book对象是MyBook或ABook类型的天气。所以我的问题是如何调用显示方法每次打印正确的书。 Book对象的ArrayList如何存储在堆上? (即所有对象都以Java语言存储在堆中)它是否将其存储为已上传的Book对象。还是将它存储为实际的MyBook和ABook类型的对象,以便在调用display方法时,JVM明确知道MyBook或ABook上的方法将被调用?

P.S.是的例子有点不好,但假设我在MyBook和ABook上甚至没有类似的显示方法。即使如此,JVM仍然执行正确的显示方法。所以请在上传完成后解释JVM中发生了什么。

+1

调用哪个方法在编译时定义哪个方法。 – SomeJavaGuy

+0

'但是在运行时,JVM不知道数组列表上的Book对象是MyBook还是ABook类型。“它知道。 – YoungHobbit

+0

@KevinEsche那么在堆中它将被存储为Book对象吗? – StackPointer

回答

1

具体对象是ABook,声明为Book

其中display方法选择已解决在运行时,而不是编译时。

JLS

如果要被调用的方法是一个实例方法,实际 方法要被调用将在运行时来确定,使用动态 方法查找( §15.12.4)。

基本上这意味着实际的实例类型是在运行时获取的。如果该方法在该类中被覆盖,则执行该方法,如果该方法未被覆盖,则调用超类的方法。

+0

所以在数组列表中只有指向该对象的指针是正确的?并且对象完全没有被铸造,并且按类型MyBook存储在堆上? – StackPointer

+0

基本上是,在java中被称为引用,但它完全一样 –

+0

@StackPointer:对象*是*铸造的,但铸造不会改变对象,而只是引用的类型。对象的类型永远不会改变。 – Holger

0

这个概念被称为多态性。 ABook是一本书 MyBook是一本书

你可以有一个ArrayList,并有ABook和MyBook的内部对象。 但是每次你得到这个ArrayList的一个对象时,你只能调用book的方法,除非你对这个子类中的一个进行了downcast。但是在转换之前你必须确定子类,因为你可能会得到CastException。

最后,如果您调用覆盖方法,那么在运行时他总是会调用对象方法。在运行时,他总是调用对象方法。

1

您在混合对象和引用。您从不在ArrayList中存储对象,只是将参考存储到对象。引用可能比它所指向的对象具有更宽的类型,但不会更改对象的实际类型。

事实上,由于类型擦除,一个ArrayList<Book>甚至不包含类型Book的引用,它有没有关于它的知识。它只包含Object类型的引用,但这对于ArrayList按其所需的全部工作就足够了,即在java.lang.Object中声明的方法boolean equals(Object)。由于引用的类型不会更改实际对象的类型,因此如果equals方法已被覆盖,则通过类型为Object的引用在对象上调用equals仍将调用实际类型的最具体方法。

您也可以在同一个对象多次存储在List,而“存储对象”是一个口语期限您总是有翻译为“存储对象的引用”自己。如果你这样做,仍然只有一个对象,并且列表将只包含对它的多个引用。通过这些引用之一修改该对象将立即通过所有其他引用变为可见。

当以特定实现方式创建并存储在对象中时,对象的类型是固定的。这也是为什么运行时类型将类型缩小到更具体的类型可以验证正确性的原因。演员不会改变对象的类型,只有在证明正确性后,才会从具有更宽类型的引用中创建对具有更具体类型的同一对象的新引用。当从ArrayList<Book>中检索参考时,这也会隐式发生;存储在列表中的类型Object的引用将转换为您将收到的类型为Book的引用。