user133466
user133466

Reputation: 3415

Why wouldn't polymorphism work in this case?

Object aThing = new Integer(25);

The method call aThing.intValue() is a compiler error. Why doesn't polymorphism work in this case?

Also there's a related statement in my textbook that is a bit convoluted:

The type of reference, not the type of the object referenced, determines that operations can be performed.

Can you briefly elaborate on that?

Where as Computer[] labComputers = new Computer[10]; works with polymorphism

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;
    }

}

Added: I believe somewhere in the middle, there would be

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

For the method call labComputers[1].toString(), polymophism ensures that the correct toString is called. In my mind labComputer[1] = new Notebook(2,15); is equivalent to Object o = new Integer(25);. But polymorphism worked for my Computer example not in the Object-Integer example. Why?

Upvotes: 0

Views: 324

Answers (4)

rid
rid

Reputation: 63442

Because even though Integer is an Object, Object is not an Integer and therefore it doesn't have Integer's methods, only Object's.


The type of reference, not the type of the object referenced, determines that operations can be performed.

By that they mean that even though the object that is referenced contains more functionality, if the type of the reference is different from the type of the object, then only the functionality of they type of the reference will be available.

In the following:

Object aThing = new Integer(25);

the type of aThing is declared as Object. Even though the implementation contains more than that, whatever else the implementation contains is not visible anymore, because the type of the variable is not Integer, but Object. Both Object and Integer have methods in common, but you can only access the ones provided by Object from now on, because nobody other than you know that this is really an Integer, not just an Object.


In the second example they mean that even though both Object and Integer have methods in common, when you call one of the methods, the method of the actual type will be called. So in this case, if you call toString() on aThing, you will call Integer's toString() method, not Object's. Therefore this is only an access issue. The fact that you declare it as an Object doesn't mean that you will get Object's methods to respond to calls, it only means that whatever methods that are present in Integer and not in Object will just be unavailable.


Example:

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() { ... }
}

Now let's create a Notebook:

Notebook n = new Notebook();

Suppose that you have the following method:

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

If you call this method with the Notebook you defined above:

showStatistics(n);

then the method will receive the Notebook, because a Notebook is a Computer. It can call the Notebook's getInstalledOperatingSystems() method, because any Computer has that method. When it calls it, it will receive 1 as a result, because Notebook overrides Computer's implementation. But showStatistics() will not be able to call any other method that Notebook provides, because it doesn't know that it's being passed a Notebook. For all it cares, it has a Computer, and it doesn't know of any other method that a Computer doesn't have.

You can very well send it a Desktop instead, or maybe tomorrow you will create a GamingComputer that extends Desktop or a Server class that extends Computer. You can send that as well. But showStatistics() will not have access to any of Server's specific, specialized methods, because showStatistics() doesn't know that it's looking at a Server. It wasn't even invented when showStatistics() was written.

This is consistent with the statement that even though a Server is always a Computer, a Computer is not always a Server.


You can check though. So if you know that you might be passed in a Notebook, not only a computer, you can look for that and you can even call Notebook's methods, but you have to be sure that you're looking at 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();
}

Upvotes: 5

Hot Licks
Hot Licks

Reputation: 47729

The compiler needs to be told what type it should expect the object to be, so it can look up the class and see if the method is legit.

So you can say Object aThing = new Integer(25); but then you'd want to say int thingValue = (Integer)aThing.intValue();

If you have a MySubClass object that is is a subclass of MyClass, and you want to call a method defined in MyClass (even if reimplemented in MySubClass) you could say:

Object myObject = new MySubClass();
int someValue = (MyClass)myObject.methodInMyObject();

Upvotes: 0

Luiggi Mendoza
Luiggi Mendoza

Reputation: 85779

It won't work because your variable is from Object class, so you can only use methods in the Object class. If you want to use it as an Integer, you should first do a (down) type casting:

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

Now, why could maybe work? Because downcasting could throw a ClassCastException if the type casting won't work.

Based in your example, I would post a basic code to show how polymophism works:

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();
    }
}

Upvotes: 5

Ben
Ben

Reputation: 2917

Think of it this way, a dog is an object and a dog class might have methods such as

dog.bark()

If you cast Dog up the hierarchy to an Object, it becomes less specific.

Object o = dog;

Now all you know is that o is an object, you do not know what kind of objects and therefore you cannot know if this object can bark.

When you move UP the hierarchy you almost always lose functionality by being less specific about what you have.

Upvotes: 2

Related Questions