Home > Software engineering >  I am having dificulty understanding how to create an array using generics
I am having dificulty understanding how to create an array using generics

Time:05-22

I am a bit stuck on a homework assignment, I am currently trying to create a new array using generics, I am able to create the array by casting the object first. However, I am running into an object cannot be cast to class error when I have < extends Comparable<? super T> in the class.

How am I supposed to create an array of generics that contains comparables?


 public void insert(T x) {
       if(currentSize == 0){
           System.out.println("yes");
           array = (T[]) new Object[10];
           array[currentSize] = x;
       }```


CodePudding user response:

Let's ignore generics for a minute and say you have

class Foobar {
    ...
}

If you try to do

Foo f = (Foobar) new Object();

You will clearly get a compiler error because you cannot cast Object to Foobar.

So what about arrays?

Foo[] fs = (Foobar[]) new Object[10];

This will give a compiler error as well because you can't cast an array of Object to an array of Foobar.

In your particular case, you just need to create an array of Object:

array = new Object[10];

CodePudding user response:

I am having dificulty understanding how to create an array using generics

No doubt. You see, what you want is impossible.

Arrays, fundamentally, are 'reified' - given an array, any array, you can write code that, at runtime, obtains the component type:

String[] x = new String[0];
Object o = x;
System.out.println(o.getClass().getComponentType());

Will get the job done.

In rather sharp contrast, generics are erased. This information is simply not available. Given:

List<String> x = new ArrayList<String>();
System.out.println(x.????());

There is nothing. No call, no method, no hack, nothing. There is no way to obtain 'oh, it is a list of strings' from a reference to a list. Instead, generics are 100% a compiler song and dance routine: The compiler does it all, it uses the generics to know that certain types in different locations are identical and makes things act as if they are, and generates invisible casts to make it all work at runtime:

List<String> x = new ArrayList<String>();
x.add(5); // This is an error only because the compiler says so.
String y = x.get(0); // This is compiled to: String y = (String) x.get(0);.

This explains why what you want is simply completely impossible. Inside the insert method, the compiler has no idea what T is, and at runtime, the JVM won't know either. However, arrays do know. You can't create something out of nothing: Hence, you cannot create an array like this.

But.. what about (T[])?

The cast operator is used for 3 completely and utterly unrelated things. One of them, is 'type coercion' - you are simply telling the compiler: Yeah yeah. Trust me. It's an X. The compiler will not insert a type test at all. It results in zero bytecode. It's just a 'compiler hint'. If you stick generics in those ()? That's type coercion. It changes nothing and checks nothing (and always gets you a warning, because it's rather useless, and you're intentionally disabling type safety by doing so). Thus, you CAN cast stuff to (T[]). But this neither converts a thing to actually be an array of Ts, nor does it even check. Hence, trying to cast new Object[10] to (T[]) doesn't work unless T happens to be Object. If it isn't, either it flat out does not work, or later code that thinks you have an array of String, will fail, because it isn't really.

Huh? So what's the solution then?

Don't use arrays. They're primitive annoying things that you don't want to use - use List instead. Arrays are solely for building the lowest level of APIs. For example, ArrayList itself uses an internal array.

If you are writing such a thing yourself, never use a T[], Just make an Object[], and type-coerce (ignoring the warnings) everywhere that it is needed - that, or ask the user to provide either code to make that array, or the array itself, because you cannot make it if all you have is a type variable (generics).

ArrayList uses this, for example. Feel free to check the source - it has an Object[] values;, not a T[] values;. Instead, the get method is effectively return (T) values.get(idx); - that's where the cast is.

  • Related