6

This thing has me stumped. I have a class as follows:

public class SpecialList implements List<MyType> {
    // overriden methods
}

Now I have the following method contract to respect in a higher class:

public class MyClass {
    private List<SpecialList> bigList = new ArrayList<SpecialList>();

    public void doStuff(List<MyType> list)
    {
        bigList.add((SpecialList)list); // does not compile - invalid cast
    }
}

I really am not sure what I am doing wrong here. I have a class that implements the List<MyType> interface, yet I can't cast that class to a List<MyType>? That doesn't make any sense to me.

I am lost. What am I supposed to do to make this work? I suppose this has something to do with generics covariance but at this point I don't know what is wrong here. Can someone point in the right direction? Thanks.

6
  • what do you wants to do here? do you want to add teh contents of list to bigList or add list to bigList Commented May 27, 2013 at 6:42
  • Probably you need is addAll() bigList.addAll(list); Commented May 27, 2013 at 6:44
  • @ArunPJohny I want bigList to be a list of MyLists, i.e. a list of list of MyType. So addAll isn't appropriate here I think. Commented May 27, 2013 at 6:49
  • @ruakh It's the same list in both. I will change the question as you said, it is unclear I agree. Commented May 27, 2013 at 6:50
  • 2
    its compiling in my eclipse :O Commented May 27, 2013 at 7:17

7 Answers 7

3

not every List<MyType> (Animal) is MyList (Cow)

you are adding animals to list of cows

Sign up to request clarification or add additional context in comments.

1 Comment

So how can I maintain the contract of the doStuff method while still having a derived list type? Do I really need to have my own list use a generic type and cast it to MyType in every single method??
2

I would suggest some parameters :

public class MyClass{
    private List<List<MyType>> bigList = new ArrayList<List<MyType>>();

    public <E extends List<MyType>> void doStuff(E list)
    {
        bigList.add(list);
    }
}

When you retrieve an element from your bigList however you cannot specialize the element as it comes from a generic list. If you absolutely need to cast it, maybe your class architecture is not correct. Or you could abusively do this :

public class MyClass{
    private List<List<MyType>> bigList = new ArrayList<List<MyType>>();

    public <E extends List<MyType>> void doStuff(E list)
    {
        bigList.add(list);
    }

    public <E extends List<MyType>> E getStuff(Class<E> myType,int i)
    {
        List<MyType> obj = bigList.get(i);
        if(myType.isInstance(obj)) return (E) obj;
        throw new SomeErrorHere("invalid type for index");
    }
}

Comments

1

You defined List<MyList> (i.e. list of MyList). This means that you can add there instances of MyList only. If you are using addAll() you can add list of MyList. But you are trying to add List<MyType>. MyType is definitely not MyList.

And you obviously cannot cast List to MyList.

1 Comment

Re: "you obviously cannot cast List to MyList": I wouldn't say "obviously", since that is exactly what the OP is asking about. (And it's not obvious to me, either.)
1

From what I recall the proper way to typecast list is with the use of generics. Something like:

bigList.add((List<MyList>)(List<?>)list);

However I am not sure of the theory behind this code.

1 Comment

This is bad advice; it's certainly not "the proper way". The only time you would need to go through a superfluous List<?> is if you're actually casting incompatibly, e.g. you have a List<Object> and you want to re-dub it a List<String> (or vice versa). The only reason you can get away with it is that these casts can't be checked at runtime.
1

Why is this error occurring

The code is formally correct. You can cast almost any object to any other object and the code will compile. If the cast is invalid, there will be a runtime ClassCastException thrown.

Your IDE can detect unsure casts and complain about them during compile time. Either as a warning or as an error. It is a matter of configuration. Apparently OPs IDE is configured to make such code smells a compile error

Why is this cast unsafe

You can answer your question by answering this:

Can you create a List<MyType> that is not a SpecialList?

You can not cast a List<MyType> to SpecialList because there may be objects which will be List<MyType> and will really not be SpecialList.

Solutions

Change your app architecture

There are two things you can do - either use the class SpecialList all accross your code, or use the generic List<MyType>.

In other words, either change:

doStuff(List<MyType> list) to doStuff(SpecialList list)

or change the

private List<SpecialList> bigList to private List<List<MyType>> bigList

You have to decide whether you want a generic interface list or your own class used everywhere. Remember, that you can alaways cast SpecialList to List<MyType>, because all SpecialList instances are also instances of List<MyType>. It does not work the other way around.

Make sure the cast will always be valid

If you absolutely HAVE TO make this design work, use instanceof to check if the list is really a SpecialList. Like that:

public void doStuff(List<MyType> list)
{
    if (list instanceof SpecialList) {
        bigList.add((SpecialList)list);
    } else {
        SpecialList sl = new SpecialList(list); // I hope you have that constructor
        bigList.add(sl);
    }
}

4 Comments

So how can I maintain the contract of the doStuff method while still having a derived list type? Do I really need to have my own list use a generic type and cast object parameters to MyType in every single method??
Neither of these options are acceptable. The first alternative breaks the doStuff method contract and the second alternative makes it impossible to control access of the MyType elements via the inner list (SpecialList). I know it's a horrible class design but I have to make it work somehow.
@Thomas added the instanceof check; please make sure you properly the not instanceof case.
@Thomas I edited the answer once more. I hope everything is clear now. Just add the instanceof check I posted and you'll be good.
0

This works in my Eclipse , this is class SpecialList , Hello is MyType kind of class

package a;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class SpecialList implements List<Hello> {

    //Overridden methods
    }

This one is Myclass

package a;

import java.util.ArrayList;
import java.util.List;

public class MyClass {
    private List<SpecialList> bigList = new ArrayList<SpecialList>();

    public void doStuff(List<Hello> list)
    {
        bigList.add((SpecialList)list);  //compiles good
    }
    public static void main(String[] args) {
        new MyClass().doStuff(null);
    }
}

No compile time error or Runtime Exception

5 Comments

You have different eclipse settings than the OP. You will get a runtime ClassCastException in case the list is not a SpecialList.
yes ofcourse i will get exception if it is not SpecialList , but here it is not giving any compiler error , OP is saying a compile time error !!
Go to your eclipse settings, in warnigns/errors section you can select what kind of reaction should Eclipse have if it detects such cases; it can be treated as a compile time error, or it can be ignored. It's up to the programmer to set these. I like them to be as defensive as possible, you apparently do not. It's your choice.
your point is not addressing any of this , does OP declare any eclipse or compiler setting change ??
@Dariusz: Can you give more details about this option? My version of Eclipse does not seem to have it; when I open my preferences and filter the Errors/Warnings section by cast, the only option that appears is the setting for "Unnecessary cast or 'instanceof' operation".
0
List <MyList> is not same as List <MyType>.

Lets make it simple ,look at the next few lines :

 *List<MyList> myList = new ArrayList<MyList>(); //1
  myList.add(new MyType);//2 ......Compile ERROR*

If you try to add MyType instance into List<MyList> it will give ERROR.

Why :

  • Generics means parameterized type.
  • Generic adds the TYPE SAFETY.
  • That means ,With generic all cast are automatic and implicit ,
    they dont require typecasting while adding and retriving the object
    from list explictly.

Real Time Scenario:

If the department of motor vehicles supplies a list of drivers. We think that a List<Driver> is a List<Person>,assuming that Driver is a subtype of Person.

If that the case , We could add new people who are NOT drivers into the list.

That is All Person are NOT Drivers .

Solution to above problem :

You can use Wildcards with Generics . Check this link from doc http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

1 Comment

This is not the case. He is adding a list to a list of lists.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.