3

I have an abstract class with generic (T1) that extends my Filterable interface:

public abstract class AbstractAdapter < T1 extends Filterable, T2 extends AbstractAdapter.Cell > extends ArrayAdapter < T1 > {

    public abstract class Cell {
        public T1 info;
        //...
    }

    public abstract void setData(T2 cell, int position);

    //...
}

And i have concrete class with method (setData) and Cell class implementations:

public class ConcreteAdapter extends AbstractAdapter < InfoClass, ConcreteAdapter.Cell > {

    public class Cell extends AbstractAdapter.Cell {
        //...
    }

    @Override
    public void setData(Cell cell, int position) {
        InfoClass info = (InfoClass)cell.info; // need to cast from Filterable to InfoClass (why?). Or i have compilation error
    }

    //...
}

So, i have ConcreteAdapter class with first generic class as InfoClass (that extends Filterable), in method setData i have Cell class object, but field "info" i see just as Filterable, not InfoClass. I think, field "info" already should be as generic type, because it declared as

T1 info;

but not

Filterable info;

Is it possible change field type from extendable to generic class without cast? Or its a bug in IDE?

Airfreshener
  • 826
  • 1
  • 8
  • 18
  • Possible duplicate of [Java Raw Type and generics interaction](http://stackoverflow.com/questions/1206028/java-raw-type-and-generics-interaction) – Julien May 18 '16 at 11:01
  • 1
    It's wrong to assume that the only `Cell` object that can be passed to `ConcreteAdapter.setData` is `ConcreteAdapter.Cell`. What if I'm doing a virtual call on an object with static type `AbstractAdapter` and I pass in a different `Cell` object? – aioobe May 18 '16 at 11:17
  • @aioobe, you're right, but in my case these concrete adapters uses localy and they isolated from one another. – Airfreshener May 18 '16 at 11:30
  • The compiler doesn't know that though. – aioobe May 18 '16 at 11:32

1 Answers1

5

This is a very tricky case because the AbstractAdapter is raw in AbstractAdapter.Cell. If you specify enough types, then you don't need the cast anymore:

public abstract class AbstractAdapter < T1 extends Filterable, T2 extends AbstractAdapter<T1, T2>.Cell > extends ArrayAdapter < T1 > {
    //...
}

and

public class ConcreteAdapter extends AbstractAdapter < InfoClass, ConcreteAdapter.Cell > {

    public class Cell extends AbstractAdapter<InfoClass, ConcreteAdapter.Cell>.Cell {
        //...
    }

    @Override
    public void setData(Cell cell, int position) {
        InfoClass info = cell.info; 
    }

    //...
}

makes it work again. However, it's very complicated. I would move Cell into a top-level class if possible.

Tamas Rev
  • 7,008
  • 5
  • 32
  • 49
  • Your welcome :) The `?` wildcards were bothering me so I refined the code a little. You can see on the updated answer how you can get rid of those. – Tamas Rev May 18 '16 at 11:24