Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast to an abstract class...how this is possible?

I am actually reading a book about design patterns in java and I am a newbie :)

http://www.amazon.com/Design-Patterns-Java-TM-Software/dp/0321333020/ at the chapter about composite pattern I came across a code that puzzles me, a cast to an abstract class, I have also not well understood what happens when the sub-clase calls the constructor of the abstract superclass, can you help me please!

The cast that I am talking about is in the isTree(Set visited)

        MachineComponent c = (MachineComponent) i.next();
        if (visited.contains(c) || !c.isTree(visited)) 

      

How can we call the isTree method of the subclass after a cast to his abstract superclass while the isTree superclass method is abstract?

Here are snippets of the two classes:

package com.oozinoz.machine;
/*
 * Copyright (c) 2001, 2005. Steven J. Metsker.
 */

import java.util.*;
import com.oozinoz.iterator.ComponentIterator;

/**
 * Objects of this class represent either individual machines or composites of
 * machines.
 */

public abstract class MachineComponent {

    /*
     * Subclasses implement this to support the isTree() algorithm.
     */

    protected abstract boolean isTree(Set s);
 
    // rest of class omitted
}

2:

package com.oozinoz.machine;    
/*
 * Copyright (c) 2001, 2005. Steven J. Metsker.
 */

import java.util.*;
import com.oozinoz.iterator.ComponentIterator;
import com.oozinoz.iterator.CompositeIterator;

 /**
 * Represent a collection of machines: a manufacturing line, a bay, or a
 * factory.
 */

public class MachineComposite extends MachineComponent {
    protected List components = new ArrayList();

    /**
     * @param visited a set of visited nodes
     * @return true if this composite is a tree
     * @see MachineComponent#isTree()
     */

    protected boolean isTree(Set visited) {
        visited.add(this);
        Iterator i = components.iterator();
        while (i.hasNext()) {
            MachineComponent c = (MachineComponent) i.next();
            if (visited.contains(c) || !c.isTree(visited)) 
                return false;
        }
        return true;
    }

    // rest of class omitted
}
like image 573
user1125516 Avatar asked Jan 02 '12 00:01

user1125516


3 Answers

This is the distinction between runtime type (actual type) and compile-time type.

The typecast to an abstract class MachineComponent is fine, because the actual object instance will actually be some non-abstract subclass of MachineComponent that implements all of the abstract methods.

The abstract MachineComponent class is the compile-time type of the assigned variable. But no actual instance is (or can be) created with that abstract class.

like image 164
wrschneider Avatar answered Oct 14 '22 19:10

wrschneider


The isTree is only abstract for the abstract class. Once the class has been initialized as a non-abstract, casting it to an abstract will not change its memory. Therefore, calling the method on an abstract class effectively calls it on the concrete implementation.

The reason why it's useful is for passing subclasses around via the abstract implementation.

Let's say a String class has 'length' method. There's no need to have a function for every possible String-type subclass. Instead, you cast to the basic (abstract) String that has the 'length' implementation, and pass that around.

like image 43
AWF4vk Avatar answered Oct 14 '22 20:10

AWF4vk


OK - let's try again:

Q: Can you cast to an abstract class?

A: Sure - of course you can

For example:

public class UseAbstract
{
  public static void main (String[] args)
  {
    // Instantiate an abstract class
    AbstractPet myDog = new Dog ();
    myDog.sound ();

    // Instantiate a concrete class
    Cat myCat = new Cat ();
    myCat.sound ();

    // Cast a concrete class to an abstract class
    AbstractPet somePet = (AbstractPet)myCat;
    somePet.sound ();
  }
}

abstract class AbstractPet
{
  void sound ()
  {
    System.out.println ("eek");
  }
}

class Dog extends AbstractPet
{
  void sound ()
  {
    System.out.println ("Woof");
  }
}

class Cat extends AbstractPet
{
  void sound ()
  {
    System.out.println ("meow");
  }
}
like image 3
paulsm4 Avatar answered Oct 14 '22 20:10

paulsm4