0

I've two classes that use generic types (A, B). My question is - What is the best way to work with the first generic type (TA) from inside B ? Here is simplified example:

public class A<TListItemsType>
{
    List<TListItemsType> list = new LinkedList<TListItemsType>();
    public List<TListItemsType> getList()
    {
        return list;
    }   
}
public class B<TContainderType extends A>
{
    TContainderType temp = null;
    public B(TContainderType cont)
    {
        temp=cont;  
    }
    public void DoWork()
    {
        for (TListItemsType item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

I've tried the solution suggested here -

public class B<TContainderType extends A<TListItemsType>>
{
    TContainderType temp = null;
    public B(TContainderType cont)
    {
        temp=cont;  
    }
    public void DoWork()
    {
        for (TListItemsType item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

And it works as long as use pre defined type such as Integer or String, sadly, this doesn't work as the compiler doesn't recognize the generic as class name.

So went further on and tried to configure another generic type and then use it inside the extends:

public class B<TListItemsType, TContainderType extends A<TListItemsType>>
{
    TContainderType temp = null;
    public B(TContainderType cont)
    {
        temp=cont;  
    }
    public void DoWork()
    {
        for (TListItemsType item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

And it actually works, but it doesn't smell right. Is there another way to use generic type used n another generic type?

Community
  • 1
  • 1
SimSimY
  • 3,616
  • 2
  • 30
  • 35
  • 1
    Sorry but it is extremely annoying that your actual class names are single character names and your type parameters long. It should be the other way around and it makes the code incredibly hard to read. – biziclop Dec 04 '12 at 16:06
  • Well @biziclop, I think is pretty clear that in this case important part is the generic type rather than the class name, and that this is very simplified example, giving single character names to the generics would make the code completely unreadable. I can assure you that in RL the classes have full names :) – SimSimY Dec 04 '12 at 19:44
  • The opposite is true: this is making the code unreadable. Single character names for generics are fine, it's what everyone is used to. – biziclop Dec 04 '12 at 20:04

2 Answers2

1

The way you did it using B<TListItemsType, TContainderType extends A<TListItemsType>> looks good to me...

The reason this makes sense is that your B class now indeed needs two parameters to describe it: TListItemsType and TContainderType. In fact, you are even using TListItemsType explicitly in your DoWork() function inside B. So it's only fair that you need to pass it as a parameter. Otherwise the compiler wouldn't even know what you mean inside your DoWork() function, as you could just as well write the class definition like this:

public class B<TWorkItemType, TContainderType extends A<TWorkItemType>>
{
    //...

    public void DoWork()
    {
        for (TWorkItemType item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

(Notice that I a renamed the type entirely, but just in B, not in A!)

If it simply required you to use the same name TListItemsType as used in the definition of A, you would be quite limited in the things you could do with generics. For example, you could not accept one type extends List<E> and another extends Enum<E>, since both of these used <E> as their generic identifier.

I hope it smells better now... :)

Markus A.
  • 12,349
  • 8
  • 52
  • 116
0

It's really unclear from your question what requirements you need, and what you need to use TListItemsType for. If you really don't need to use TListItemsType in a meaningful way (as it looks like in your example), you could eliminate it and just have TContainderType extend A<?>:

public class B<TContainderType extends A<?>>
{
    TContainderType temp = null;
    public B(TContainderType cont)
    {
        temp=cont;  
    }
    public void DoWork()
    {
        for (Object item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

and for that matter, if you are not going to return TContainderType or use it in a type parameter or something, you can even eliminate that:

public class B
{
    A<?> temp = null;
    public B(A<?> cont)
    {
        temp=cont;  
    }
    public void DoWork()
    {
        for (Object item : temp.getList())
        {
            System.out.println(item);
        }
    }
}

So it all depends on what you need to do. Your example doesn't do much, so it is possible to remove a lot of things from it, but that may not be what you actually need.

newacct
  • 119,665
  • 29
  • 163
  • 224