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
}
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.
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.
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");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With