Your solution doesn't work. Here, trivial test case to make it fail:
var set = new ArraySet<Number>();
set.add(5); // adds an integer
set.add(10.0); // adds a double
This code should be completely fine. Both integers and doubles are, after all, subtypes of number. But that will fail, with an ArrayStoreException
, because you end up making a Integer[]
under the hood which will throw that exception when you try to shove a Double in there.
This is ridiculously hard.
That's a really funny way of saying "this is impossible". Because it is impossible, not 'hard'. Unless you classify impossible as a particularly egregious case of 'hard', which, I guess, why not :)
The reason it is impossible is that java erases this stuff. If what you wanted was possible, then someone would have written a reifiable version of ArrayList 15 years ago (Reifiable is, amongst other things: You can ask the ArrayList at runtime what its component type is).
Conclusion
You / your boy misunderstood the assignment. That, or, the teacher is clueless. It's possible.
So what should you do?
The java community at large knows exactly how to do this, and it is with an Object array. Here is the source code of java.util.ArrayList
which is:
- Exactly the functionality you seem to have been asked to implement.
- Is, outside of
java.lang
, the most used java class on the planet.
- As a general rule, the openjdk team knows what they are doing.
They use Object[]
. Because it's the right way to do this. E[]
? Fundamentally wrong - it's not possible to make those, at best you can ugly-cast an Object[] to it, but it's still an Object[] - just cast to a type it really is not, with the compiler warnings that go along with doing stuff that doesn't really make sense.
What does the assignment want you to do?
Who knows - as I said, you misunderstood, or the teacher is clueless / this is one of those socratesian projects whose aim is for you to learn that this doesn't work, maybe.
One option, but this is strictly worse, it has no benefits and quite a few downsides, is to require the code that constructs one of these ArraySet
objects to pass in the type. It looks like this:
class ArraySet<E> {
E[] data;
public ArraySet(Class<E> type, int capacity) {
this.data = Array.newInstance(type, capacity);
}
// ....
}
But this has quite a few downsides:
- The caller now needs to explicitly pass in stuff. They HAVE to write:
ArraySet<String> myStrings = new ArraySet<>(String.class, 20);
... for absolutely no good reason whatsoever. This code isn't any faster and it's not any 'safer' unless the user of your library is in the habit of intentionally ignoring compiler warnings. Which gets us to a simple adage: Ooooh, trust me, programming is hard and morons are incredibly inventive. You cannot stop an idiot from creating bugs in this way. This is a very counterproductive lesson if that is the stated reason for trying to do it this way.
Class<E>
cannot, itself, convey generics. If you want to create an ArraySet<String>
that doesn't matter much. But imagine you are trying to make an ArraySet<FileSystem<Path>>
for example. That simply doesn't work. FileSystem<Path>.class
isn't a thing (class objects cannot convey generics).
So, you've made it harder to use your arrayset, and completely eliminated a sizable batch of use cases (all cases where the element type itself also contains generics), for absolutely no relevant gain of any sort.
You now have a strong appeal to authority (openjdk team itself uses an Object[]), as well as 2 strong objective reasons (needlessly complicated to call the constructor, eliminates significant use cases for no gain).
If this teacher explains their bizarre thoughts (or, the assignment was misunderstood), if you could report back to sate my curiosity I would appreciate it :)