views:

139

answers:

3
+1  Q: 

Stack of elements

How do I insert elements of different data types into a single stack in Java?

+10  A: 

It seems to defeat the purpose of generics, but here it goes:

Stack<Object>s = new Stack<Object>();
s.add("hello");
s.add(1);           // int is autoboxed to Integer

The catch will be that when retrieving the Objects from the Stack, it's going to take some effort to find out what type of each element is -- it will require using instanceof and typecasts:

while (!s.isEmpty()) {
  Object e = s.pop();

  if (e instanceof String)
    System.out.println("String: " + (String)e);
  else if (e instanceof Integer)
    System.out.println("Integer: " + (Integer)e);
  else
    System.out.println("Other type: " + e);
}

And now, we have something resembling the fragile code of the pre-Java 5 days before generics was added to the language.

coobird
The danger is when you retrieve the items later on, you have to write checks for object types.
Joset
Absolutely -- I just finished adding that part in as an edit.
coobird
+6  A: 

Generally, you'll want to solve this using inheritance. Possibly using a marker interface:

interface MyMarker
{
}

class Foo implements MyMarker
{
}

class Bar implements MyMarker
{
}

Interfaces are practical in cases like this, because you can implement an unlimited number of interfaces in a single class, and you can add extra interfaces anywhere in the class hierchy.

You can then put Foo and Bar in the same stack:

Stack<MyMarker> s = new Stack<MyMarker>();
s.add(new Foo());
s.add(new Bar());

This is the way to go if it's at all possible. Otherwise you'll have to do it like coobird suggests.

Emil H
This is definitely a better way -- whenever there's a if-elseif ladder of "instanceof"s, the solution is usually inheritance.
coobird
A: 

The generic argument of the stack should be a common super type of all the element runtime types. For completely heterogeneous collections, Object is the common super type of all reference types. So:

Queue<Object> stack = Collections.asLifoQueue(new ArrayDeque<Object>());
stack.add("red");
stack.add(Color.GREEN);
stack.add(stack);

Obviously you when you come to pop those elements off the stack you will need to do instanceof checking to route to appropriate code (and probably cast).

Probably better is to introduce a layer of indirection. Instead of putting the objects on the queue directly, wrap them in a meaningful object. The instanceof checks can all be replace by calls to (virtual) methods that perform the operations you require. This is how polymorphism is supposed to be.

Tom Hawtin - tackline