将对象投射到 class

Cast an Object into a class

我正在尝试将对象转换为 class 实例。 classes实例的Object当然应该继承所有的方法。

所以这是示例代码 (2) 中的问题,因为我无法准确解释我的意思:

Class Fish {}
Class Dog {}

class Instances() {

    private Fish fish = new Fish();
    private Dog dog = new Dog();

    public Object getInstance(String className) {

        if( className.equals("fish") ) 

            return fish;

        else

            return dog;

    }

}

class test() {

    Instances in = new Instances();

    public static void main(String[] args) {

        // 1: works (transmits all the methods of fish)
        Fish fish = (Fish)in.getInstance("fish");

        // 2: doesn't work (fishObj only has access to the methods of an object and can't access the methods of Fish!)
        Object fishObj = null;
        fishObj = (Fish)in.getInstance("fish");

    }

}

提前致谢!

   Object fishObj = null;
    fishObj = (Fish)in.getInstance("fish");

对象被转换为带有 (Fish) 的 Fish,但是由于您的引用是对象引用,它随后被扩展回对象,因此您看到的只有这些方法。

((Fish)fishObj ).printFish();

首先,你的Instances in = new Instances(); 应该是静态的,因为您在静态变量中使用它

您已将 Fish 对象分配给基本 java 对象

这称为运行时多态性或动态方法调度是一个过程,在该过程中,对重写方法的调用在运行时而不是编译时解析。 More

当您将对象引用分配给变量时,您将对该引用变量执行的任何进一步操作仅限于为其类型定义的操作。

因此您可以将 Fish 分配给 Object 变量。但是只要使用Object变量,就只能使用Object中定义的方法,如toString()hashCode()

但是您在评论中指出,您想 运行 在两个 class 中使用类似的方法。我假设这意味着你的 DogFish classes 有一个具有相似名称、参数和 return 类型的方法,例如 getLegCount() 将 return 4 Dog0 Fish.

出现这种情况时,您要么必须将这两种类型都声明为另一个 class 的子class,它具有所需的方法:

public abstract class Animal {

    public abstract int getLegCount();

}

class Fish extends Animal {

    @Override
    public int getLegCount() {
        return 0;
    }
}

然后 getInstance() 中的 return 类型应该是 Animal,而不是 Object。而你把结果放在一个Animal变量中,然后就可以使用getLegCount()方法了。

另一种选择是将所需的常用方法定义为接口。它的工作方式相同,如果在预期的 Animal 类型中没有实现细节,只有方法定义,则更可取:

public interface Animal {

    int getLegCount();

}

class Fish implements Animal {
    @Override
    public int getLegCount() {
        return 0;
    }
}

同样,您可以将 getInstance 中的 return 类型声明为 Animal,将您的变量声明为 Animal 而不是 Object

java 编译器将阻止您在 fishObj 上使用除 Object 之外的任何方法,因为您将变量 fishObj 声明为 Object。编译器无法预测在 运行 时间该变量将实际引用什么类型的对象,因此它通过声明进行。

当然,你我都知道 fishObj 会在方法被调用时持有对 Fish 的引用,但通常弄清楚这些事情并不总是可能,Java 编译器不会尝试。

你的演员表什么也没做。它通知编译器表达式的值实际上是 Fish,但随后您将该值分配给类型为 Object 的变量,并且编译器对该变量的看法没有任何改变。 (你的演员表唯一可能的影响是如果 #getInstance 实际上返回了一些不是 Fish 的东西,在这种情况下你会在 运行 时得到 ClassCastException。 )

您可以使用 Java 的反射 类 获取无法通过变量的声明类型访问的对象的方法。例如:

fishObj.getClass().getMethod("swim").invoke(fishObj);

让我们看一下您的一些代码:

Object fishObj = null;
fishObj = (Fish)in.getInstance("fish");

那么为什么可以将 class Fish 的对象分配给数据类型为 Object 的变量? 在 Java 中,每个 class 都派生自 class Object,因此 Object 是每个 class 的超 class。我们可以将 subclass 的对象分配给 superclass 的变量。这就是你在这里所做的。

fishObj = (Fish)in.getInstance("fish");

您将 class Fish 的对象分配给变量 fishObj。这是可能的,因为 Fish 扩展了 Object(即使您没有明确指出)。 所以我们可以说 fishObj 具有静态类型 Object(在本例中为通用数据类型)和动态类型 Fish(分配给变量的 Object)。

静态类型定义哪些方法是可访问的,而动态类型定义方法的行为方式。

那是什么意思?让我们看看Oracle Documentation for the class Object。 我们可以看到它有多种方法,如 hashCode() 或 equals()。如果静态类型是Object,所有这些方法都可以调用,因为每个subclass都需要有这些方法。所以无论发生什么,调用都不应该失败。

假设您的 class Fish 有方法 swim() 并再次查看一些代码。

Object fishObj = new Fish();

那么这里的静态类型和动态类型是什么? 对象将是静态类型,再次钓鱼动态类型。 现在我们不想做下面的调用。

fishObj.swim(); //won't work

为什么会这样?静态类型Object 的class 没有名为swim() 的方法。所以我们不能肯定地说,我们可以分配给变量 fishObj 的每个对象都一定会实现 mehtod swim()。

总而言之,由于您的静态类型是 Object,class Fish 的特定方法对您是隐藏的,以确保对分配给变量 fishObj 的对象的调用始终有效.