0
Object aThing = new Integer(25);

方法调用aThing.intValue()是编译器错误。为什么多态在这种情况下不起作用?

在我的教科书中还有一个相关的陈述有点令人费解:

引用的类型,而不是引用的对象的类型,决定了可以执行的操作。

你能简要说明一下吗?

asComputer[] labComputers = new Computer[10];与多态一起工作

public class Computer {
    int ram;
    public Computer(int rm){
        ram= rm;
    }
    public String toString(){
        String result = "ram is " + ram;
        return result;
    }
}


public class Notebook extends Computer{
int size;
public Notebook(int rm, int sz){
    super(rm);
    size = sz;
}
@Override
    public String toString(){
        String result = super.toString() + " size is " + size;
        return result;
    }

}

补充:我相信在中间的某个地方,会有

labComputer[1] = new Notebook(2,15);
labComputer[2] = new Computer(2);

对于方法调用labComputers[1].toString(),多态确保调用正确toString。在我心目中labComputer[1] = new Notebook(2,15);相当于Object o = new Integer(25);。但是多态性适用于我的计算机示例而不是 Object-Integer 示例。为什么?

4

4 回答 4

5

因为即使Integer是一个ObjectObject也不是一个Integer,因此它没有Integer' 方法,只有Object'。


引用的类型,而不是引用的对象的类型,决定了可以执行的操作。

这意味着即使被引用的对象包含更多功能,如果引用的类型与对象的类型不同,那么只有引用类型的功能可用。

在下面的:

Object aThing = new Integer(25);

的类型aThing被声明为Object。即使实现包含更多内容,但实现包含的任何其他内容都不再可见,因为变量的类型不是Integer,而是Object。两者ObjectInteger有共同的方法,但从现在开始你只能访问由提供的方法Object,因为除了你之外没有人知道这真的是一个Integer,而不仅仅是一个Object


在第二个示例中,它们意味着即使两者Object都有Integer共同的方法,但当您调用其中一个方法时,将调用实际类型的方法。所以在这种情况下,如果你调用toString()on aThing,你会调用Integer'stoString()方法,而不是Object's。因此,这只是一个访问问题。将其声明为 an 的Object事实并不意味着您将获得Object' 的方法来响应调用,它仅意味着存在Integer和不存在的任何方法都Object将不可用。


例子:

class Computer {
    public int getInstalledOperatingSystems() { return 3; }
}

class Desktop extends Computer {
    public String getShapeOfCase() { ... }
}

class Notebook extends Computer {
    public int getInstalledOperatingSystems() { return 1; }
    public String getBrand() { ... }
    public void closeLid() { ... }
}

现在让我们创建一个Notebook

Notebook n = new Notebook();

假设您有以下方法:

public String showStatistics(Computer computer) {
    result = "Operating systems: " + computer.getInstalledOperatingSystems();
    return result;
}

如果您使用Notebook上面定义的方法调用此方法:

showStatistics(n);

然后该方法将收到Notebook,因为 aNotebook是 a Computer。它可以调用Notebook'getInstalledOperatingSystems()方法,因为任何人Computer都有该方法。当它调用它时,它会收到1结果,因为NotebookoverridesComputer的实现。但是showStatistics()将无法调用Notebook提供的任何其他方法,因为它不知道它正在传递一个Notebook. 尽管它关心的是,它有 a Computer,并且它不知道 aComputer没有的任何其他方法。

您可以很好地发送它Desktop,或者明天您将创建一个GamingComputer扩展Desktop或扩展的ServerComputer。你也可以发送那个。但showStatistics()将无法访问任何Server特定的、专门的方法,因为showStatistics()知道它正在查看Server. 它甚至在showStatistics()编写时都没有被发明。

这与即使 aServer总是 a Computer, aComputer并不总是 a的陈述是一致的Server


你可以检查一下。因此,如果您知道您可能会传入 a Notebook,而不仅仅是一台计算机,您可以查找它,甚至可以调用Notebook's 方法,但您必须确保您正在查看 a Notebook

if (computer instanceof Notebook) {
    // this is definitely a Notebook, so you can assure the compiler
    // of that explicitly, by using a cast
    Notebook notebook = (Notebook) computer;

    result += "This isn't just a generic computer, it's actually a notebook! ";

    // now that you have a variable of type Notebook, you can call
    // whatever Notebook provides
    result += "It's produced by: " + notebook.getBrand();
}
于 2012-10-14T23:14:08.007 回答
5

它不起作用,因为您的变量来自Object类,因此您只能使用 Object类中的方法。如果您想将其用作Integer,您应该首先进行(向下)类型转换:

Integer aInteger = (Integer)aThing;
//it could maybe work
aInteger.intValue();

现在,为什么可能工作?因为如果类型转换不起作用,向下转换可能会抛出 ClassCastException。

根据您的示例,我将发布一个基本代码来展示多态性是如何工作的:

class Animal {
    public void move() {
        System.out.println("I'm an animal and I can move.");
    }
}

class Cat extends Animal {
    //this means a Cat would change the move behavior from the Animal instance
    @Override
    public void move() {
        System.out.println("I'm a cat and I can move.");
    }
}

class Dog extends Animal {
    //this means a Cat would change the move behavior from the Animal instance
    @Override
    public void move() {
        System.out.println("I'm a dog and I like to run.");
    }
    public void bark() {
        System.out.println("I can bark!");
    }
}

public class AnimalTest {
    public static void main(String[] args) {
         //it will take the behavior of the Animal class reference
         Animal animal = new Animal();
         //it will take the behavior of the Cat class reference
         Animal cat = new Cat();
         //it will take the behavior of the Dog class reference
         Animal dog = new Dog();
         //this will invoke the Animal#move method
         animal.move();
         //this will invoke the Cat#move method because it was overriden in the Cat class
         cat.move();
         //this will invoke the Dog#move method because it was overriden in the Dog class
         dog.move();
         //this line won't compile if uncommented because not all animals can bark.
         //dog.bark();
         //if you want to make the dog barks, then you should use the downcasting
         ((Dog)dog).bark();
         //note that this will only work for Dog class reference, not for any other class
         //uncomment this line and the code will compile but throw a ClassCastException
         //((Dog)cat).bark();
    }
}
于 2012-10-14T23:15:06.680 回答
2

这样想,狗是一个对象,狗类可能有诸如

dog.bark()

如果您将 Dog 向上投射到一个对象,它就会变得不那么具体。

Object o = dog;

现在你只知道 o 是一个物体,你不知道什么样的物体,因此你不知道这个物体是否会吠叫。

当您向上移动层次结构时,您几乎总是会因为对所拥有的内容不那么具体而失去功能。

于 2012-10-14T23:17:04.293 回答
0

编译器需要被告知它应该期望对象是什么类型,因此它可以查找类并查看该方法是否合法。

所以你可以说Object aThing = new Integer(25);但是你会想说int thingValue = (Integer)aThing.intValue();

如果您有一个 MySubClass 对象,它是 MyClass 的子类,并且您想调用在 MyClass 中定义的方法(即使在 MySubClass 中重新实现),您可以说:

Object myObject = new MySubClass();
int someValue = (MyClass)myObject.methodInMyObject();
于 2012-10-14T23:30:22.997 回答