【问题标题】:Cast an Object into a class将对象转换为类
【发布时间】:2015-05-27 18:27:16
【问题描述】:

我正在尝试将 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 引用访问它,为什么您认为它应该可以访问Fish 方法?
  • 您已经知道如何编写有效的代码 (1),那您还问什么?
  • @Eran 因为这两个类中的方法正在执行类似的任务并且它们具有相同的名称。我想加载我当前需要的类
  • 如果您想使用Fish 方法,您必须将其存储为Fish,或将其在同一行 转换为Fish(例如((First) in.getInstance("fish")).swim(). 没有办法。
  • @Aurus 听起来您希望两个类都实现相同的接口(包含常用方法)并将getInstance 的返回类型更改为该接口。

标签: java eclipse class subclass


【解决方案1】:

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

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

但是您在 cmets 中指出您希望在两个类中运行类似的方法。我假设这意味着您的 DogFish 类具有具有相似名称、参数和返回类型的方法,例如 getLegCount() 将返回 4 用于 Dog0 用于 Fish

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

public abstract class Animal {

    public abstract int getLegCount();

}

class Fish extends Animal {

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

然后你的getInstance() 的返回类型应该是Animal,而不是Object。然后将结果放入Animal 变量中,然后可以使用getLegCount() 方法。

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

public interface Animal {

    int getLegCount();

}

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

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

【讨论】:

  • 您的两个答案都正是我想要的,即使我的问题表述错误,谢谢!
【解决方案2】:

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

当然,你和我都知道fishObj 在调用该方法的那一刻将持有对Fish 的引用,但通常情况下并不总是能够弄清楚这些事情,Java 编译器没有尝试。

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

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

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

【讨论】:

    【解决方案3】:

    让我们看看你的一些代码:

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

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

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

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

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

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

    假设你的类 Fish 有方法 Swim() 并再次查看一些代码。

    Object fishObj = new Fish();
    

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

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

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

    总而言之,我们可以说,由于您的静态类型是 Object,因此类 Fish 的特定方法对您隐藏,以确保对分配给变量 fishObj 的 Object 的调用将始终有效。

    【讨论】:

    • 我在这里对我的问题的第一个回答,所以如果有些东西没有完全充实,请原谅;)
    【解决方案4】:
       Object fishObj = null;
        fishObj = (Fish)in.getInstance("fish");
    

    使用 (Fish) 将对象强制转换为 Fish,但由于您的引用是 Object 引用,因此它会被扩展回 Object,因此您看到的只有这些方法。

    【讨论】:

      【解决方案5】:
      ((Fish)fishObj ).printFish();
      

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

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

      【讨论】:

        【解决方案6】:

        这称为运行时多态性或动态方法分派,是在运行时而不是编译时解决对被覆盖方法的调用的过程。 More

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-11-27
          • 2018-04-13
          • 1970-01-01
          • 1970-01-01
          • 2022-09-29
          • 1970-01-01
          • 2013-09-03
          相关资源
          最近更新 更多