2

I don't understand why I get ClassCastException on below code in line:

for(int i = 0; i < k.t.length; i++)

So problem is that in method addElement I make replacing of array elements by objects with type T. In my opinion in array should be objects with type T. And compiler doesn't protest for that. But in run-time JVM cannot cast despite in array is really objects with type T (in case below String), why JVM cannot use polymorphism?

But when I change the T[] t; to Object[] t;

and remove cast in constructor it run correctly without any errors, why?

public class MyCollection<T> {

    T[] t;

    MyCollection( int size){
        t = (T[]) new Object[size];
    }

    boolean addElement(T e, int i){        
        if(i < t.length){
            t[i] = e;
            return true;
        }
        return false;            
    }

    public static void main(String[] ss){

        MyCollection<String> k = new MyCollection<String>(3);

        k.addElement("a",0);
        k.addElement("b",1);
        k.addElement("c",2);

        for(int i = 0; i < k.t.length; i++)
            System.out.println(k.t[i]);     

        //for(String s : (String[])k.t)
        //    System.out.println(s);        
    }
}
4
  • Maybe you need k.t[0].toString() Commented Jun 8, 2014 at 8:12
  • @algui91: no, println already does that. Commented Jun 8, 2014 at 8:12
  • stackoverflow.com/questions/529085/… Commented Jun 8, 2014 at 8:21
  • @algui91 The problem isn't on System.out.println(k.t[0]); but on for(int i = 0; i < k.t.length; i++) Commented Jun 8, 2014 at 8:44

3 Answers 3

4

The problem is that you're casting Object[] to T[], and then you're exposing the underlying array. The only reason this works altogether is because the type erasure of T is Object. But since in our case T is being interpreted as String, when we access the array externally, we're trying to cast it to String[], which is incorrect. In order to avoid this issue, you should make the array private and provide accessor methods to retrieve elements. By doing that, you only cast individual elements to their correct type without making assumptions about the underlying array.

public class MyCollection<T> {

    private T[] t;

    MyCollection( int size){
        t = (T[]) new Object[size];
    }

    boolean addElement(T e, int i){        
        if(i < t.length){
            t[i] = e;
            return true;
        }
        return false;

    }

    T getElement(int index) {
        return t[index];
    }

    int getLength() {
        return t.length;
    }

    public static void main(String[] ss){

        MyCollection<String> k = new MyCollection<String>(3);

        k.addElement("a",0);
        k.addElement("b",1);
        k.addElement("c",2);

        for(int i = 0; i < k.getLength(); i++)
            System.out.println(k.getElement(i));     

        //for(String s : (String[])k.t)
        //    System.out.println(s);        
     }
}

Note that Java's Collection interface demonstrates the same behavior. Collection.toArray() returns Object[] regardless of the type of E. The only available workaround is Collection.toArray(T[]), where you're forced to pass an array with a fixed type, which can then be either be populated or copied.

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

3 Comments

It would also break type-safety to allow such a cast (Object[] to T[]), as there is no way to statically determine whether your Object-array contains only T's.
@SebastianOkon As long as the array is internally managed, you can be certain it will always contain Ts. In that case, using an array of T lets you skip casting values to T upon retrieval.
I did not meant to disagree to you. If it is implemented like this it is fine. Nevertheless this is potentially dangerous as you do not get any warning in case you make some changes/extensions later.
1

Check again the line of the problem. In my opinion the exception will be thrown because of:

    for(String s : (String[])k.t)

You`re trying to cast to String[] here, while the array is defined as Object[]:

t = (T[]) new Object[size];

3 Comments

But he says the error is in the first loop for(int i = 0; i < k.t.length; i++)
The sample problem occurs in the first loop. It's really equivalent to for (int i = 0; i < ((String[])k.t).length); i++).
You can look how own collection with array can be made in grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
0

you can Create a new instance of array using the reflection to avoid ClassCastException

example:

    import java.lang.reflect.Array;

public class MyCollection<T> {

    T[] t;

    MyCollection(Class<T> clazz, int size) {
        t = (T[]) Array.newInstance(clazz, size);

    }

    boolean addElement(T e, int i) {
        if (i < t.length - 1) {
            t[i] = e;
            return true;
        }
        return false;

    }

    public static void main(String[] ss) {

        MyCollection<String> k = new MyCollection<String>(String.class, 3);

        k.addElement("a", 0);
        k.addElement("b", 1);
        k.addElement("c", 2);

        for (int i = 0; i < k.t.length; i++)
            System.out.println(k.t[0]);

    }
}

3 Comments

I know that I can do that. But I'm instresting why I cannot do as I write.
So problem is that in method addElement I make replacing of array elements by objects with type T. In my opinion in array should be objects with type T. And compiler doesn't protest for that. But in run-time JVM cannot cast despite in array is really objects with type T (in case below String), why JVM cannot use polymorphism?
@LunaVulpo that is beause java doesnt know what T is and therefore cant use polymorphism due to that.

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.