Java 动态、静态投射

Java dynamic, static casting

import javax.swing.*;

public class Toast {
    static Object[] objects = { new JButton(),
        new String("Example"), new Object() };

    public static void main(String[] args) {
        System.out.println( new Count(objects) );
        for (Object o : objects)
            System.out.println(o);
    }
}


class Count {
    int b, s, o;
    public Count(Object[] objects) {
        for (int i=0; i<objects.length; i++)
            count(objects[i]);
    }
    public void count(JButton x) { b++; }
    public void count(String x) { s++; }
    public void count(Object x) { o++; }
    public String toString() {
        return b + " : " + s + " : " + o + "\n";
    }
}

以上是一段代码,它以某种形式出现在我即将进行的一项考试的过去试卷中。这个问题的目的是衡量你是否完全理解多态性、动态和静态转换。 OO的基本思想。

我想发表我认为正确的内容,如果人们能够纠正我或添加要点,我们将不胜感激。

从上面的代码可以看出:

我看不到与上述代码相关的任何其他要点。

以下是我要带走的内容:

  1. 编译器在执行赋值时隐式向上转型。这包括在初始化期间分配给数组元素。

  2. 编译器和 JVM 在选择方法重载时不会隐式向下转换。对象数组的静态类型是Object[],所以count(Object)方法总是会被调用。

  3. JVM 在调用虚方法时隐式地"downcast"(某种意义上)。 println 循环将始终调用实际对象实例的 toString 方法,而不是始终调用 Object.toString.

在您的 Count() 方法中,将始终调用 count(object),因为所有对象都向上转换为 object。 为防止您可以调用方法实例,然后向下转换对象并调用计数

public Count(Object[] objects) {
    for (int i=0; i<objects.length; i++)
    {
        if(objects[i] instanceof JButton)
           count((JButton) objects[i]);
        else if(objects[i] instanceof String) 
           count((String) objects[i]);
        else
           count(objects[i]);
    }
} 

静态转换和动态转换背后的思想与需要做出类型决定的时刻有关。如果它需要由编译器制作,那么它就是静态转换。如果编译器将决定推迟到运行时,那么它就是动态转换。

所以,你的第一个观察是不正确的。 upcast 不解释计数。对象不会松散它们的类型,但编译器需要执行 static cast 来决定调用哪个方法并选择 count(Object)。 java 中没有动态调度,这意味着调用的方法总是在编译时决定的。

你的第二个观察也不正确。使用的是多态性。在 Java 中,方法总是针对实例的类型调用,而不是针对代码中的类型。此外,这里没有动态转换。编译器可以验证所有类型。只是方法调用总是 virtual 但这不是强制转换。

实际上在这个例子中,我没有看到一个动态转换的案例。编译器可以验证所有类型。您通常只会在向下转换时看到动态转换,而没有这种情况。