Reputation: 1151
I've got a problem with my Java code. I want to make my method universal with using of generics types. It's easier to explain it with code:
public interface Destroyable {
void destroy();
default void destroyArray(byte[] array) {
Arrays.fill(array, (byte)0);
}
default void destroyArray(char[] array) {
Arrays.fill(array, (char)0);
}
}
The point is, that I want my default method destroyArray to work with any type, like this:
public interface Destroyable {
void destroy();
default <E> void destroyArray(Class<E>[] array) {
Arrays.fill(array, (E)0);
}
}
It gives me error:
Inconvertible types; cannot cast 'int' to 'E'
Is there any simple solution to achieve this?
Upvotes: 4
Views: 1669
Reputation: 109557
Your original approach with many overloaded methods is fine.
For primitive types, the generics would work for their arrays as:
default <A> void destroyArray(A array) {
Class<?> arrayType = array.getClass();
if (!arrayType.isArray()) {
return;
}
Class<?> type = arrayType.getComponentType();
if (type == int.class) {
Arrays.fill((int[])array, 0);
} else if (type == char.class) {
Arrays.fill((char[])array, '\0');
}
//...
}
As you can see: this is hardly more compact, slower and less type safe, and secure forgotten primitive types.
Upvotes: 2
Reputation: 271645
default <E> void destroyArray(E[] array) {
Arrays.fill(array, null);
}
The above might be what you intended. However, this wouldn't work with primitive types. Because primitive types are not allowed to be passed as generic type parameters, you will still need a destroyByteArray
, destroyIntArray
etc.
Also, destroyArray
doesn't seem to belong in Destroyable
. Shouldn't it just be in a helper class full of static methods? If I were you I would move it to there. It does not even call the destroy
method, so it has no reason to be in Destroyable
.
Upvotes: 4
Reputation: 25903
The problem with your code:
default <E> void destroyArray(E[] array) {
Arrays.fill(array, (E) 0);
}
is that a general E
type is of course not necessarily an int
(or something that can be autoboxed like Integer
). But you want to actually write some default value. Therefore you would need to create valid instances of E
. Which, in general, is hard because you don't know anything about the type, including its constructors.
However, there is one valid value for all Object
s, namely null
. It indicates that there simply is no instance at the moment.
So the following would work for arbitrary types E
:
default <E> void destroyArray(E[] array) {
Arrays.fill(array, null);
}
However, with that you are still not able to fill primitive-type arrays like int[]
since E
can only be used for Object
s, not primitives. You would need to hard-code additional methods for each primitive:
default void destroyArray(int[] array) {
Arrays.fill(array, 0);
}
default void destroyArray(double[] array) {
Arrays.fill(array, 0.0);
}
// ...
Class<E>
Your original code had Class<E>[]
instead of E[]
. Note that Class<E>
means something completely different than E[]
.
Class<E>
is a Class
object, a wrapper that provides Reflection-API access to analyze contents of the class. Like getting names of methods and stuff like that. Whereas E
is the class itself.
So Person
would be a Person
class and Class<Person>
is like a class which knows stuff about the Person
class, like its method names.
See the documentation of Class
for more details.
Upvotes: 9