DSlomer64
DSlomer64

Reputation: 4283

Using generic linked list but forced to use (cast) when popping

I am deliriously overjoyed to say that I just implemented a generic linked list from a few weeks ago in a project and IT WORKS! One problem, though. I am forced to do a cast (and didn't expect to).

Here are some snippets, I hope enough to define problem, starting with the generic stack:

    public class GenericStack<E> {

      public LinkedList <E> stack = new LinkedList<>();

      public void push (E obj){
        stack.add(obj);
      }

      public E pop() {
        if (stack.isEmpty()) return null;
        return stack.removeLast();
      }
      ...
}

Here's the class defintion in which I use the generic stack:

public class Grid extends GenericStack<JTextField> implements ActionListener, KeyListener, KeyCodes

Here's me defining stack and what I'm pushing and popping:

  GenericStack stack = new GenericStack();
  public static JTextField[][] cells = new JTextField[11][11];

Here's me pushing onto stack:

 stack.push(Grid.cells[currentCell.row][currentCell.col]);

Here's where I pop from stack, which works ONLY IF I DO THE CAST shown:

  private void calculate(){
    JTextField w = new JTextField();
    while(stack.size()>0){
      w =  (JTextField) stack.pop();
      System.out.println("stack element " + w.getText());
    }
  }

Now I'm not complaining; I'm not even sure there's a problem to deal with, but without the cast (JTextField), I get "INCOMPATIBLE TYPES--REQUIRED: JTextField; FOUND: Object" but stack.pop() is clearly defined to return the generic type, which is JTextField, so why do I need to cast?

Upvotes: 0

Views: 176

Answers (3)

DSlomer64
DSlomer64

Reputation: 4283

D'OH!!

So happy it worked I overlooked a few obvious (to experienced folk) things (that I truly have no excuse for overlooking), so yes, I made the change Rohit Jain suggested (after noting same from Jon Skeet) and I've got a sleeker method of popping:

  private void calculate(){
    while(stack.size()>0){
      System.out.println("stack element " + stack.pop().getText());
    }
  }

(Method's called calculate because it's GOING TO do so soon.)

But, Jon, I don't see how my code indicates that I'm mixing composition and inheritance, but maybe that's because I don't fully understand either just now!

I'll tell ya this, though: the daily (day-long??) frustration just to get one more line of code to work are over. Java rocks! (once you get to a certain point on the learning curve!) I'm stunned at how far I've come on this in just a couple of days! (OK, maybe coffee helped!)

Upvotes: 0

Rohit Jain
Rohit Jain

Reputation: 213223

You have used raw type of your generic type in the following instantiation:

GenericStack stack = new GenericStack();  

When you use raw types, all the generic type inside the class is replaced by their raw type counterpart, and the type parameters are replaced by their erasures. Since erasure of E in your case is Object, as it doesn't have any bound. So, the linked list, and methods:

public LinkedList <E> stack = new LinkedList<>();
public void push (E obj) { ... }
public E pop() { ... }

will be erased to:

public LinkedList stack = new LinkedList();
public void push(Object obj) { ... }
public Object pop() { ... }

hence, you get back Object type, when you invoke pop() method.

What you need is a parameterized instantiation:

GenericStack<JTextField> stack = new GenericStack<>();

And of course, what JonSkeet said in his answer. Don't mix-up inheritance and composition. You are having a reference of type GenericStack, and also extending it. It doesn't make sense. Follow the advice in Jon's answer.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500405

This is the problem:

GenericStack stack = new GenericStack();

That's using the raw type of GenericStack. It's not clear why you've got this at all when you've already extended GenericStack<JTextField> to be honest. I'd expect you to either use composition:

public class Grid implements ActionListener, KeyListener, KeyCodes {
    private final GenericStack<JTextField> stack = new GenericStack<JTextField>();

    private void calculate() {
        while (stack.size() > 0) {
            JTextField w = stack.pop();
            System.out.println("stack element " + w.getText());
        }
    }
}

or use inheritance:

public class Grid extends GenericStack<JTextField> 
    implements ActionListener, KeyListener, KeyCodes {

    private void calculate() {
        while (size() > 0) {
            JTextField w = pop();
            System.out.println("stack element " + w.getText());
        }
    }
}

At the moment you're mixing the two, which is really odd.

Upvotes: 4

Related Questions