8

我想弄清楚为什么我需要向下转换。我从拼贴中重新阅读了我的笔记,并找到了以下示例。

class Student {...}

class Graduate exteds Student {
   getResearchTopic(){...} // this method only exists in Graduate class.
}

我们有一个 Student 类的引用,并希望访问 getResearchTopic 方法;

Student s1 = new Graduate();
if(s1 instanceof Graduate){
   ((Graduate)s1).getResearchTopic();
}

向下转换的好例子哈?我的问题是为什么不首先将 s1 宣布为毕业生?是否有一个现实生活中的例子,我将不得不向下转换而不是使用实际类的实例?

4

5 回答 5

7

好吧,您可以将引用声明s1为 type Graduate。通过声明 的引用,您获得的主要好处super type多态性的强大功能。

使用超类型引用,指向一个子类对象,您可以将同一个引用绑定到多个子类对象。调用的实际方法将在运行时根据所指向的对象来决定。但是,这样做的主要条件是,该方法也应该在子类中定义,否则编译器将无法找到方法声明。

在这里,您被迫这样做downcast,因为您还没有在超类中定义方法。Student由于编译器无法在类中看到该方法的定义。它不知道实际对象s1指向什么。请记住,编译器仅检查引用类型以查找方法声明。

通常,每当您看到自己在代码中向下转换为子类时,这几乎总是表明有问题(但也有一些例外)。你应该修改你的类。


让我们看看使用超类引用而不是子类引用可以获得什么好处:

例如:假设您有另一个子类Studentas:

class Phd extends Student {
    getResearchTopic(){...}
}

并且您还在Student课堂上提供了一个定义(默认定义):

class Student {
    getResearchTopic(){...}
}

现在,您创建以下两个对象,它们都被Student引用指向:

Student student = new Phd();
student.getResearchTopic();   // Calls Phd class method

student = new Graduate();
student.getResearchTopic();    // Calls Graduate class method

因此,只需一个引用,您就可以访问特定于子类的方法。


您可以在factory method模式中看到此功能的一个主要实现,其中单个静态方法根据某些条件返回不同子类的对象:

public static Student getInstance(String type) {
    if (type.equals("graduate")) 
        return new Graduate();
    else if (type.equals("phd"))
        return new Phd();
}

因此,您可以看到相同的方法返回不同子类的对象。

你可以做以上所有事情只是因为一个概念:

Super 类引用可以引用任何子类对象,但反之则不行

于 2013-07-16T19:12:01.447 回答
6

假设您有一个将 aStudent作为参数的方法。它所做的大部分事情对所有学生都是通用的。但是,如果它是 a Graduate,它可能还会做其他事情。在这种情况下,您需要确定Student传入的内容是否实际上是 aGraduate并在该实例中执行一些特殊逻辑。

也许是这样的:

class StudentDAO {
    public void SaveStudent(Student s) {
       // Do something to save the student data to a database.

       if ( s instanceof Graduate ) {
           // Save their research topic too.
       }
    }
}

请注意,做这种事情通常是一种糟糕的编程习惯,但有时它是有意义的。

于 2013-07-16T19:12:56.400 回答
1

当您使用默认的 Java 反序列化器反序列化对象时,您将使用此代码(并且在使用另一个反序列化器时使用类似的代码,例如 Jackson JSON 反序列化器)

ObjectInputStream ois = new ObjectInputStream(in);
Object obj = ois.readObject();

然后你需要转换obj成它的实际类型,因为readObject()总是会返回一个普通的旧Object的——该方法不能静态地验证正在读取什么类型的对象

于 2013-07-16T19:16:24.900 回答
0

在您想使用多态性的情况下,最好使用Student对象,然后“向下转型”以使用特定于Graduate对象的方法。

通常,如果您有一个处理Student对象的方法,该方法在编译时并不真正知道Student传入的是什么特定类型的对象。因此,在运行时,该方法应该检查特定类型和进程因此。

于 2013-07-16T19:12:39.963 回答
0

当您尝试创建泛型方法时,向下转换确实有帮助。例如,我经常看到将 XML 解析StringObject. 然后Object可以将其转换为Object您(作为编码人员)知道它所代表的具体内容。

private static XStream xstream = new XStream(new DomDriver());
static {
    xstream.processAnnotations(MyFirstClass.class);
    xstream.processAnnotations(MySecondClass.class);
    // ...
}

public static Object fromXML(String xml) {
    return xstream.fromXML(xml);
}

这让我可以创建一个非常通用的方法,它可以在所有情况下执行我希望它执行的操作。然后,当我调用它时,我可以简单地将其转换Object为我知道它将成为的样子。它使我不必为每种对象类型创建单独的解析方法,并提高了我的代码的可读性。

MyFirstClass parsedObject = (MyFirstClass) MyXMLTransformer.fromXML(xml);
于 2013-07-16T19:13:11.413 回答