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?
Default value of objects
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 Objects, 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);
}
Primitives
However, with that you are still not able to fill primitive-type arrays like int[] since E can only be used for Objects, 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);
}
// ...
Note on 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.
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.
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.
Related
An error occurs at new T[5] during compile-time saying => error: generic array creation
and according to my understanding, the array is created during compile-time and since we don't know the type of T at compile-time we cannot instantiate an array.
But
if T gets erased at compile-time and changes to Object then still why this error occurs ? because we can create an array of Object.
// Before Compiling
public class GenericClass<T> {
GenericClass(){
T[] obj = new T[5];
}
}
// After Compiling
public class GenericClass {
GenericClass() {
Object[] obj = new Object[5];
}
}
Similar case, like,
public class GenericClass<T> {
GenericClass(){
T obj = new T(); }}
/* error :required: class
found: type parameter T
where T is a type-variable:
T extends Object declared in class GenericClass*/
according to my understanding, the array is created during compile-time
No, the array is created at runtime.
nd since we don't know the type of T at compile-time we cannot instantiate an array.
Correct.
But if T gets erased at compile-time and changes to Object then still why this error occurs ?
Because "it is erased at compile time and changes to Object" is oversimplified.
Also, generics and arrays don't play nice with each other. The problem is, where the generics part is erased, arrays do not work like that. You can do this:
String[] x = new String[10];
tellMeTheTypeOfMyArray(x);
void tellMeTheTypeOfMyArray(Object[] o) {
System.out.println("Your array's component type is: " + o.getClass().getComponentType());
}
This code will compile and work fine, without error, and prints:
Your array's component type is: java.lang.String
Contrast to generics where you cannot write such a method. You cannot possibly make this:
List<String> x = new ArrayList<String>();
tellMeTheTypeOfMyList(x);
void tellMeTheTypeOfMyList(List<?> o) {
System.out.println("Your list's component type is: " + ??????);
}
work. There's no java code possible here, nothing you can write in place of the ?????? to print String, because that information simply is not there at runtime anymore.
Imagine this code:
// This is written by Wahab today.
class Example<T> {
protected T[] arr;
Example() {
this.arr = new T[10];
}
}
and it worked like you wanted. Then I do:
// Written by me, a year later
class Uhoh extends Example<String> {
Uhoh() {
super();
}
void hmmm() {
System.out.println(this.arr.getComponentType());
}
}
I would obviously expect, nay, demand - that this prints java.lang.String, but it could not possibly do so. Because this is weird and confusing, java has a rule: If you compile your code and you do not see any warnings about generics problems (and did not #SuppressWarnings them away), then this kind of confusion is not likely to happen.
Allowing you to write new T[] and having that just be a silly way to write new Object[] is considered too far gone for this.
So how do I use arrays with generics types?
The same way java.util.ArrayList does it: Do not use generics here. Arrays should pretty much never have T types if you intend to create them inside the generic code. If you have a T[] anywhere in your codebase, then that means you should never be new-ing up anything for it - let the caller of your code do it for you. If you do want to new up new arrays yourself, don't use T, use Object[] as type, and cast to T where needed. This is literally how java's built-in ArrayList class works. Some excerpts copy-pasted straight from its source:
transient Object[] elementData; // non-private to simplify nested class access
public E get(int index) {
Objects.checkIndex(index, size);
return elementData(index);
}
#SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
Here's an example, again straight from ArrayList's sources (or rather, java.util.Collection defines this, and ArrayList inherits it), where you let the caller provide you with code to make arrays:
default <T> T[] toArray(IntFunction<T[]> generator) {
return toArray(generator.apply(0));
}
Here the caller provides a function that transforms an int into a T[] - it takes the concept of doing new String[10] and turns it into a function, that you then pass along to the toArray method which will then use it (feel free to ignore how it uses it here, it's a bit of a bizarre solution. It works, just - not sure you should be learning lessons about that part).
You use it like this:
List<String> listOfStrings = ...;
String[] convertedToArray = listOfStrings.toArray(String[]::new);
Java arrays know their component type at runtime. When you create an array, you must provide the component type at runtime. But in your GenericClass, it cannot do that because it does not know what T is at runtime. If it creates an Object[], that object will have the wrong runtime class, and that instance is not compatible with the type T[] if T is anything other than Object. You are correct that, within the class, nothing is immediately wrong. But if the claim that the variable is T[] is exposed to an outside scope which expects T to be a more specific type, it can cause a ClassCastException:
// Before type erasure
class GenericClass<T> {
T[] obj;
GenericClass() {
obj = new T[5]; // if hypothetically you could do this
}
T[] getObj() {
return obj;
}
}
class MyCode {
public static void main(String[] args) {
GenericClass<String> foo = new GenericClass<>();
String[] strings = foo.getObj(); // no casts needed; no warnings
}
}
// After type erasure
class GenericClass {
Object[] obj;
GenericClass() {
obj = new Object[5];
}
Object[] getObj() {
return obj;
}
}
class MyCode {
public static void main(String[] args) {
GenericClass foo = new GenericClass();
String[] strings = (String[]) foo.getObj(); // ClassCastException at runtime
}
}
for performance reasons I need to use arrays to store data. I implemented this in a generic fashion like this (see this answer):
import java.lang.reflect.Array;
public class SimpleArray<T> {
private T[] data;
#SuppressWarnings("unchecked")
public SimpleArray(Class<T> cls, int size) {
this.data = (T[]) Array.newInstance(cls, size);
}
public T get(int i) {
return data[i];
}
}
The problem is that I need the involved Class<?>es. However, I might have a more complex class hierarchy containing generics:
public class Outer<T> {
public class Inner {
}
}
I would like to initialize the array as I would with an ordinary class:
SimpleArray<Integer> intArray = new SimpleArray<>(Integer.class, 10);
intArray.get(0);
SimpleArray<Outer<Integer>> outerArray;
// how to initialize this?
SimpleArray<Outer<String>.Inner> innerArray;
// how to initialize this?
I read the post on how to (not) get the Class of something generic (here) but the bottom-line seems to be that everything is type-safety related syntactic sugar.
My question is the following: How can I create instances of the SimpleArray classes above while avoiding as much ugliness as possible?
There are two issues here.
Do you really need to pass in a Class? In this case, no. Your class does not actually need to know the element type at runtime to do its job. For example, you can just do:
public class SimpleArray<T> {
private Object[] data;
public SimpleArray(int size) {
this.data = new Object[size];
}
#SuppressWarnings("unchecked")
public T get(int i) {
return (T)data[i];
}
}
If you really needed a Class<T>, how would you get one? Well, first you need to ask yourself, what are you going to use this for? There will never be a "true" Class<T> for a non-reifiable type T because with a Class<T> you can do things like .isInstance() to check whether something is an instance of T at runtime; but of course it's not possible to check instance-of with non-reifiable types at runtime.
In this case, you're only going to pass it to Array.newInstance(), and Array.newInstance() uses the raw type anyway (it does not care about the compile-time type of the Class parameter -- the parameter type is Class<?> -- it only uses the runtime value of the Class object), it is sufficient to simply coerce a Class object representing the raw type to the appropriately-parameterized Class type:
(Class<Outer<Integer>>)(Class<?>)Outer.class
You seem to be trying to make a class that wraps an array and provides a method to get elements. The class Arrays.ArrayList does exactly that already, so there is no need to reinvent the wheel. It works as follows:
List<String> list = Arrays.asList(new String[30]);
list.set(3, "foo");
System.out.println(list.get(3));
You can't use Arrays.asList to produce a List<T> if the type T is generic without suppressing a warning because it is not possible to create a generic array. You can write a helper method to do this for you though.
#SuppressWarnings("unchecked")
public static <T> List<T> newArray(int size) {
return (List<T>) Arrays.asList(new Object[size]);
}
You can use the returned List to get and set elements without having to cast, even if the type T is generic. For example:
List<List<String>> list = newArray(30);
list.set(4, Arrays.asList("A", "B", "C"));
System.out.println(list.get(4));
See Boolean#TYPE for an example of what I'm referring to.
All of the wrapper classes (Boolean, Double, Integer, etc) have a static Class field associated with them called TYPE. What is the meaning of this?
Specifically, here are a few soft tests:
System.out.println(Boolean.class == Boolean.TYPE);
System.out.println(Boolean.TYPE.isInstance(Boolean.valueOf(true)));
Both evaluate as false. (And as a side note, an .equals comparison is unnecessary since Class does not override equals from Object.)
Both Boolean.class and Boolean.TYPE are Class<Boolean> because they are == comparable without an error. Comparing two objects with differently declared generic types is illegal.
On further inspection, the TYPE fields are retrieved by calling a package-private native method Class#getPrimitiveClass along the lines of the following:
public static final Class<Boolean> TYPE = Class.getPrimitiveClass("boolean");
The comment on the method itself is not particularly informative either. It says it returns the VM's class object for the type which is fairly obvious since it is a native method.
I can't find any documentation on this beyond the Java docs' vague allusion to "representing the primitive type". Is there some kind of use for this field? It's unused in the wrapper classes themselves.
(Edited)
System.out.println(boolean.class == Boolean.TYPE);
Is true.
Also one use is then reflection:
try {
Constructor ctor = Boolean.class.getConstructor(Boolean.class);
} catch (Exception e) {
System.out.println("NoSuchMethodException gets thrown");
}
try {
Constructor ctor = Boolean.class.getConstructor(Boolean.TYPE);
System.out.println(ctor.newInstance(true));
} catch (Exception e) {
// (no exception thrown)
}
And I've found some SO threads that cite that, such as this one. I guess I came from the "wrong end" of Google so-to-speak to not find any results on it.
But considering the existence of the "primitive classes" (boolean.class, int.class etc.) that doesn't really explain the TYPE field existence. Basically it's "just there"? I still don't really get it.
The class representing the primitive type is useful in specifying or examining methods that take or return primitives. For example, if your class has a method that looks like this
class Test {
static int round(float val) {...}
}
and you wish to access this method through reflection, you would need to do this:
Method round = Test.class.getMethod("round", Float.TYPE);
You can examine the return type, too:
if (round.getReturnType == Integer.TYPE) {
System.out.println("Method 'round' returns an int.");
}
Using Float.class instead
Method round = Test.class.getMethod("round", Float.class);
would not work, because that would pull a different method - this one:
static int round(Float val) {...}
(Don't have the rep to comment, so must answer.)
To put it succinctly: Float.TYPE == float.class, and Float.class != float.class. Consider:
class Test {
void func() {
Class clazz;
// The two statements do the same thing. On my system, they even compile
// to the same bytecode.
clazz = Integer.TYPE; // explicitly asking for this
clazz = int.class; // must yield the same object as above.
// Both of these below are valid, as the `true' is autoboxed. In
// Java < 1.5, both had to be explicitly boxed
Test.class.getMethod("test", Boolean.class).invoke(this, true);
// calls method A
Test.class.getMethod("test", boolean.class).invoke(this, true);
// calls method B. Could also use getMethod("test", Boolean.TYPE)
}
void test(Boolean b) { System.out.println("Method A"); }
void test(boolean b) { System.out.println("Method B"); }
}
I would assume both int.class andInteger.TYPE have been around from the beginning of Java, though I may be wrong. Integer.TYPE can be initially assigned with Class.getPrimitiveClass("int").
I didn't even know this was doable, but I saw while perusing some code online a method with a signature like this:
public List<Void> read( ... )
... What? Is there ever a reason to do this? What could this List even hold? As far as I was aware, it's not possible to instantiate a Void object.
It is possible that this method signature was created as a by-product of some generic class.
For example, SwingWorker has two type parameters, one for final result and one for intermediate results. If you just don't want to use any intermediate results, you pass Void as the type parameter, resulting in some methods returning Void - i.e. nothing.
If there were a method List<V> returnAllIntermediateResults() in SwingWorker with Void as the type parameter V, it would have created a method just like you posted in your question.
The code would be perfectly valid. You can instantiate any implementation of the List interface (e.g. ArrayList) with type parameter Void. But the only value a Void type can have is null. So the list could not hold anything else but nulls, if the implementation allows null elements.
One case in which it may be useful is if you wanted to return a collection of return values from a function. Say
static List<T> forEach(Func<A,T> func, List<A> items) {
List<T> ret = new List<T>();
for(int i = 0; i< items.length; i++) {
ret.add(func.call(items[i]);
}
return ret;
}
public static void main() {
...
List<Void> boringResult =
forEach(
new Func<Void, Integer> {#override Void call(Integer i) {...}});
}
Not that useful but you could see a case where it was required.
List<Void> is weird. It can only have null elements, since you can't create an object of type Void. I don't think there is a practical use for such a thing.
Void is part of java.lang. It's not a special keyword or anything. It's a "pseudo-type" (according to the docs) used to as a place-holder to represent the Class object corresponding to void, as in Class<Void>. From the docs for Class:
The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.
The Void class exists mainly for the sake of the last part of this, so you can write:
Class<Void> voidType = void.class; // == Void.TYPE
just like you can write:
Class<Integer> intType = int.class; // == Integer.TYPE
I agree, it's odd.
I can see a use for it if you want to extend a generic class and return void from a method. I've bumped into a case were I want to use int and had to use Integer because java generics don't like primitive types.
public interface ObjectUserPool<E, T> {
public E useObject(T o);
}
public class NonReturningObjectUserPool extends ObjectUserPool<Void, Integer> {
public Void useObject(Integer i);
}
I think this is what the java API is saying, though to be honest I can't really find a use for NonReturningObjectUserPool.
I would like to return 2 different types of class (List<double[]> or List<Double[]) from a single method , as in the below pseudo code. How to achieve this ?
EDITED code and comment : Eclipse does even not allow to compile as this is requested to change the return or data type. I understand YserieScaledCasted will have to be casted manually.
protected List<E[]> getYserieRescaledList(Class<E> c) {
if (Double[].class == c)
return this.YserieScaled;
else if (double[].class == c)
return this.YserieScaledCasted;
}
EDIT2: I found the correct to my problem is simply to overload the method as described here.
You realise you are returning a list of arrays, right? :-)
Short answer:
even though you are passing in Class<E>, you can't use the instanceof operator on a generic type so you can't carry out the if-statement sketched above
the following is ILLEGAL and doesn't compile at each of the two instanceof operators:
class trash {
protected <T> List<T[]> getYserieRescaledList(Class<T> cl) {
List<T[]> result = null;
if (cl instanceof Class<Double>) {
result = ...;
} else if (cl instanceof Class<double>) {
result = ...;
}
return result;
}
}
the reason for this is that generics are a compile-time only construct. All instantiated generic classes are converted to non-generic classes, with types inserted and type casting carried out etc. It makes no sense to ask whether a generic class is instantiated with a particular type at runtime - the generic classes have been swapped for non-generic classes
Instead, cut out the if-statements and simply use the instantiated type to declare variables & arrays, then use your algorithm to populate them and return the result:
class treasure {
protected <T> List<T[]> getYserieRescaledList(Class<T> cl) {
List<T[]> result = null;
// apply general algorithm here to populate the array
// will work identically whether instantiated with Double or double
return result;
}
}
Longer Answer:
Generic classes should represent "template logic" of generalised processing that can be applied with various specific instantiated types.
Good examples are the java Collections, a persistence query framework (such as JPA Criteria API), a financial calculator for different types of investments, or even a SOA service template with standard service "container" infrastructure logic.
In your case, it might be simpler to use pseudo- method overloading (i.e. two methods with slightly different names):
protected List<Double[]> getYserieRescaledList() {
return this.Y;
}
protected List<double[]> getYserieRescaledList2() {
return this.YCasted;
}
Or even better, just stick to double[] as the only case. The compiler will transparently do autobox conversions from double to Double as needed when you extract values into other variables/method parameters.
Just use Double[].class and double[].class. Note that you can't cast a Double[] to a double[] and vice versa, you have to manually copy it. So by extension, you can't cast List<Double[]> to List<double[]> either. Edit: though upon a second glance, it appears this may be the limitation you're trying to correct.
There is some interesting stuff going on here. So your List<double[]> is an List<Array> object where the Array contains primitive doubles.
I would venture to say generics is NOT the right solution here.
I think your best bet is to use the Google Lists library.
something like this:
protected List<Double[]> getYserieRescaledList() {
return this.YseriesScaled;
}
Then, whatever calls your getYseriesRescaledList() can do something like this to get a List<double[]> :
Lists.transform(getYseriesRescaledList(), toPrimitiveDouble());
This will construct a List object in one line of code, using the Function below (from Google Guava):
private Function<Double[], double[]> toPrimitiveDouble(){
return new Function<Double[], double[]>() {
#Override
public double[] apply( Double[] doubles) {
double[] doubleArray = new double[doubles.length];
int i = 0;
for (Double doubleObject : doubles){
doubleArray[i] = doubleObject.doubleValue();
++i;
}
return doubleArray;
}
};
}