在这个例子中,为什么仍然需要对一个对象进行类型转换以确定它的类型,即使在调用了getClass()之后呢?

时间:2016-09-26 14:47:08

标签: java casting

我正在关注this MOOC on OOP in Java,并提交了an example I don't fully understand。在该示例中,已创建Book类,并且它们正在为Book类构造'equals'覆盖方法。新的equals()方法接受任何对象的参数。如果该参数是具有相同名称的Book对象,并且此Book对象是announcementYear,则返回true。因为参数对象可以是Object类的任何对象,所以在调用getPublishingYear()getName()方法之前,如果在不在Book类中的对象上调用则会抛出错误, equals()方法检查以确保它确实通过此代码处理Book对象:

 if (getClass() != object.getClass()) {
        return false;
 }

这很多(我想)我理解。我不明白为什么,在上面的代码之后,他们然后将参数对象转换为Book,然后在新铸造的对象上调用getPublishingYear()getName()而不是原始对象:

Book compared = (Book) object;

if (this.publishingYear != compared.getPublishingYear()) {
    return false;
}

if (this.name == null || !this.name.equals(compared.getName())) {
    return false;
}

    return true;

如果由于上面的getClass()检查对象不是Book类型,该方法应该已经返回false,我不明白为什么这个步骤是必要的。我尝试编译没有这个额外的转换步骤,并发现该步骤确实是必要的 - 如果您不包括此步骤,编译器会在getPublishingYear()getName()上给出“无法找到符号”错误。那我错过了什么?

完整的equals()方法:

@Override
public boolean equals(Object object) {
    if (object == null) {
        return false;
    }
    System.out.println(getClass());
    if (getClass() != object.getClass()) {
        return false;
    }

    Book compared = (Book) object;

    if (this.publishingYear != compared.getPublishingYear()) {
        return false;
    }

    if (this.name == null || !this.name.equals(compared.getName())) {
        return false;
    }

    return true;
}

4 个答案:

答案 0 :(得分:2)

因为编译器不能(禁止)推断你之前的类型检查是为了在铸造之前消除不正确的对象类型而进行的。
例如,有时少就是更多:如果在下一个语句中你只是需要将您的对象转换为其中一个基类或实现的接口吗?

interface Authored {
  public getAuthorName();
}

interface Publication {
  public String getISBN();
};

public class Book
implements Authored, Publication {

// ...
  public boolean equals(Object other) {
    if (other == null) {
        return false;
    }
    if (getClass() != other.getClass()) {
        return false;
    }
    // on purpose, we use only the Publication interface
    // because we want to avoid potential misspelling or missing 
    // title, author name, etc. impacting on equality check
    // We'll consider ISBN as a key unique enough to
    // determine if two books (e.g. registered in different 
    // libraries) are the same
    Publication p=(Publication)other;
    return this.getISBN().equals(p.getISBN());
  }
}

答案 1 :(得分:1)

您必须将Object类型的对象投射到Book,因为您要使用getPublishingYear()getName()特定于Book的函数类。 Object类没有这样的方法。

答案 2 :(得分:1)

将变量转换为数据类型基本上是告诉编译器“相信我,我知道我在做什么”。在将“对象”转换为“Book”的情况下,您正在向编译器保证该对象实际上是Book并且相应地继续。它也会强迫你相信你知道自己在做什么。

编辑:我不确定你是否在问你为什么需要实际的演员表(添加“(书籍)”)或为什么你需要为Book变量进行分配。我回答了前者。如果问题是后者,答案是您需要Book变量,以便Book方法可用。

由于你有工具来做出决定,你会认为没有必要进行强制转换,因为编译器能够生成你用来做出决定的相同代码,要求你只需要进行赋值:

Book book = object;           // Wrong

而不是

Book book = (Book) object;    // Right

如果您希望编译器“只知道”Object是Book,那么每次使用Book方法时,编译器都必须测试Object。通过在赋值中明确告知它,编译器可以创建特定于Book类的代码,而无需进一步检查Object。

答案 3 :(得分:1)

if (getClass() != object.getClass()) {
    return false;
}

你可以确定你的对象是一本书,但java仍然不知道它

所以你可以保存告诉它尝试使用

进行投射
Book compared = (Book) object;