I'm writing a program and need to get the default value of datatype (for example null for List, 0 for int, false for boolean, etc...). I have this method
private static <T> T getDefaultValue(Class<T> type) {
if (!type.isPrimitive()) return null;
// something should go there
}
and I don't know how to recognize the type and return the value without errors.
I tried if (type.equals(Integer.class)) return new Integer(0);
but I get an error for the return statement Required type: T, Provided: Integer
.
How can I do that and is there any other method than mine? (I don't want the method to return Object
ofc)
Thanks!
CodePudding user response:
You can just check each primitive type manually (there are not so many primitives in Java):
@SuppressWarnings("unchecked")
public static <T> T defaultValue(Class<T> clazz) {
if (!clazz.isPrimitive()) {
return null;
}
if (clazz == int.class) {
return (T) Integer.valueOf(0);
} else if (clazz == long.class) {
return (T) Long.valueOf(0);
} else if (clazz == float.class) {
return (T) Float.valueOf(0);
} else if (clazz == double.class) {
return (T) Double.valueOf(0);
} else if (clazz == char.class) {
return (T) Character.valueOf('\0');
} else if (clazz == byte.class) {
return (T) Byte.valueOf((byte) 0);
} else if (clazz == short.class) {
return (T) Short.valueOf((short) 0);
} else if (clazz == boolean.class) {
return (T) Boolean.valueOf(false);
} else {
throw new IllegalArgumentException("Unsupported primitive type: " clazz);
}
}
To test you can use:
public static void main(String[] args) {
List.of(String.class, int.class, long.class, double.class, float.class, boolean.class, byte.class, char.class).forEach(
cls -> System.out.printf("%s - %s\n", cls.getName(), defaultValue(cls))
);
}
CodePudding user response:
In addition to Kirill's solution, I'd like to add some background reasoning.
Your approach is correct, you only need an additional (T)
cast:
private static <T> T getDefaultValue(Class<T> type) {
if (!type.isPrimitive()) return null;
if (type.equals(Integer.class)) return (T) (new Integer(0));
// and so on for the other primitive types
}
This (T)
cast will earn you a warning, as the compiler can't infer that it's in fact safe.
By writing the (T)
cast, you as the developer guarantee that in this case (being called with Integer.class
) the new Integer(0)
instance is of the requested type T
, and that's correct, as with the argument being Integer.class
, T
can only be Integer
.
You need not even consider superclass/subclass situations, as you specified an exact type <T>
, not <? super T>
or <? extends T>
, so you can be sure that the class object received as argument exactly matches the generic type T
(unless you ignore errors/warnings elsewhere).