获取Java基本types的默认值
我手边有一个java原始types:
Class c = int.class; // or long.class, or boolean.class
我想为这个类获得一个“默认值” – 具体地说,如果这个类没有被初始化的话,这个值被分配给这个types的字段。 例如,数字“0”,布尔值“假”。
有没有一个通用的方法来做到这一点? 我试过了
c.newInstance()
但是我得到一个InstantiationException,而不是一个默认的实例。
番石榴图书馆已经包含:
http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Defaults.html
调用defaultValue
将返回任何基元types(由JLS指定)的默认值,而对于任何其他types,则返回null。
像这样使用它:
import com.google.common.base.Defaults; Defaults.defaultValue(Integer.TYPE); //will return 0
这就是我的想法(虽然没有通过优雅testing):
public class PrimitiveDefaults { // These gets initialized to their default values private static boolean DEFAULT_BOOLEAN; private static byte DEFAULT_BYTE; private static short DEFAULT_SHORT; private static int DEFAULT_INT; private static long DEFAULT_LONG; private static float DEFAULT_FLOAT; private static double DEFAULT_DOUBLE; public static Object getDefaultValue(Class clazz) { if (clazz.equals(boolean.class)) { return DEFAULT_BOOLEAN; } else if (clazz.equals(byte.class)) { return DEFAULT_BYTE; } else if (clazz.equals(short.class)) { return DEFAULT_SHORT; } else if (clazz.equals(int.class)) { return DEFAULT_INT; } else if (clazz.equals(long.class)) { return DEFAULT_LONG; } else if (clazz.equals(float.class)) { return DEFAULT_FLOAT; } else if (clazz.equals(double.class)) { return DEFAULT_DOUBLE; } else { throw new IllegalArgumentException( "Class type " + clazz + " not supported"); } } }
可以通过创build一个元素的数组并获取其第一个值来获取任何types的默认值。
private static <T> T getDefaultValue(Class<T> clazz) { return (T) Array.get(Array.newInstance(clazz, 1), 0); }
这样就不需要考虑每一种可能的基元types,而创build一个元素数组的成本通常是微不足道的。
Guava的Defaults.java
的替代scheme,它可以让实现找出默认值(通过使用Antag99的答案来改进):
import static java.util.stream.Collectors.toMap; import java.lang.reflect.Array; import java.util.Map; import java.util.stream.Stream; public class DefaultValue { /** * @param clazz * the class for which a default value is needed * @return A reasonable default value for the given class (the boxed default * value for primitives, <code>null</code> otherwise). */ @SuppressWarnings("unchecked") public static <T> T forClass(Class<T> clazz) { return (T) DEFAULT_VALUES.get(clazz); } private static final Map<Class<?>, Object> DEFAULT_VALUES = Stream .of(boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class, short.class) .collect(toMap(clazz -> (Class<?>) clazz, clazz -> Array.get(Array.newInstance(clazz, 1), 0))); public static void main(String... args) { System.out.println(DefaultValue.forClass(int.class)); // 0 System.out.println(DefaultValue.forClass(Integer.class)); // null } }
你可以用reflection来做到这一点,但是把它写出来最简单,最清楚
Object defaultValue(Class cls) { Map defaults = new HashMap(); defaults.put(Integer.TYPE, Integer.valueOf(0)); defaults.put(Double.TYPE, Double.valueOf(0)); defaults.put(Boolean.TYPE, Boolean.FALSE); //... etc return defaults.get(cls); }
当然,你可能想要将映射初始化移出到构造函数或类似的初始化。
合理简洁 – 它是优雅的?
没有一个优雅的方式来做到这一点。 实际上,甚至不可能声明一个返回原始值本身的方法的签名。
最近你可以来这样的事情:
public Object defaultValue(Class cls) { if (class == Boolean.TYPE) { return Boolean.FALSE; } else if (class == Byte.TYPE) { return Byte.valueOf(0); } else if (class == Short.TYPE) { ... } else { return null; } }
基元的类variables不需要初始化或设置为默认值。 然而,在其他范围声明的variables必须被初始化,否则你会得到编译错误。
public class PrimitiveStuff { private int aInt; private long aLong; private boolean aBoolean; public PrimitiveStuff() { System.out.println("aInt : " + aInt); //prints 0 System.out.println("aLong: "+ aLong);//prints 0 System.out.println("aBoolean: " + aBoolean);//prints false } public void doStuff(){ int outherInt; System.out.println(outherInt); //will not compile } public static void main(String[] args) { new PrimitiveStuff(); }
}
根据Jack Leow的回答 ,我创build了这个类:
/** <P>{@code java InitializedObjectUtil}</P> **/ public class InitializedObjectUtil { public static final void main(String[] igno_red) { printDefault("boolean"); printDefault("char"); printDefault("byte"); printDefault("short"); printDefault("int"); printDefault("long"); printDefault("float"); printDefault("double"); printDefault("java.lang.AnythingAndEverythingElse"); } private static final void printDefault(String s_type) { Object oDflt = InitializedObjectUtil.getForClassName(s_type); System.out.println(s_type + " default is \"" + oDflt + "\""); } /** <P>The default value for a boolean is {@code false}.</P> <P>Viewed 1/21/2014 <BR><CODE><A HREF="http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html">http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html</A></CODE>:</P> <P><B>Default Values:</B> </P> <P>It's not always necessary to assign a value when a field is declared. Fields that are declared but not initialized will be set to a reasonable default by the compiler. Generally speaking, this default will be zero or null, depending on the data type. Relying on such default values, however, is generally considered bad programming style. The following chart summarizes the default values for the above data types.</P> <PRE>{@literal Data Type Default Value (for fields) -------------------------------------- byte 0 short 0 int 0 long 0L float 0.0f double 0.0d char '\u0000' String (or any object) null boolean false}</PRE> @see #getForClass(String) getForClass(s) @see #getForClassName(String) getForClassName(s) @see #DEFAULT_CHAR @see #DEFAULT_BYTE @see #DEFAULT_SHORT @see #DEFAULT_INT @see #DEFAULT_LONG @see #DEFAULT_FLOAT @see #DEFAULT_DOUBLE **/ public static final Boolean DEFAULT_BOOLEAN = false; /** <P>The default value for a char {@code '\u0000'}.</P> @see #DEFAULT_BOOLEAN **/ public static final Character DEFAULT_CHAR = '\u0000'; /** <P>The default value for a byte is {@code 0}.</P> @see #DEFAULT_BOOLEAN **/ public static final Byte DEFAULT_BYTE = 0; /** <P>The default value for a short is {@code 0}.</P> @see #DEFAULT_BOOLEAN **/ public static final Short DEFAULT_SHORT = 0; /** <P>The default value for a int is {@code 0}.</P> @see #DEFAULT_BOOLEAN **/ public static final Integer DEFAULT_INT = 0; /** <P>The default value for a long is {@code 0L}.</P> @see #DEFAULT_BOOLEAN **/ public static final Long DEFAULT_LONG = 0L; /** <P>The default value for a float {@code 0.0f}.</P> @see #DEFAULT_BOOLEAN **/ public static final Float DEFAULT_FLOAT = 0.0f; /** <P>The default value for a double {@code 0.0d}.</P> @see #DEFAULT_BOOLEAN **/ public static final Double DEFAULT_DOUBLE = 0.0d; /** <P>Get an object containing an initialized value for the static class-type.</P> @param cls_static May not be {@code null}. @return <CODE>{@link getForClassName(String) getForClassName}(cls_static.getName())</CODE> **/ public static final Object getForClass(Class cls_static) { try { return getForClassName(cls_static.getName()); } catch(RuntimeException rtx) { throw new NullPointerException("getForClass: cls_static"); } } /** <P>Get an object containing an initialized value for the type whose name is in a string.</P> <P>Idea from (viewed 1/2/2014) <BR> {@code <A HREF="https://stackoverflow.com/questions/2891970/getting-default-value-for-java-primitive-types/2892067#2892067">https://stackoverflow.com/questions/2891970/getting-default-value-for-java-primitive-types/2892067#2892067</A>}</P> @param s_type May not be {@code null}. @return If {@code s_type} is equal to<UL> <LI>{@code "boolean"}: {@link #DEFAULT_BOOLEAN}</LI> <LI>{@code "char"}: {@link #DEFAULT_CHAR}</LI> <LI>{@code "byte"}: {@link #DEFAULT_BYTE}</LI> <LI>{@code "short"}: {@link #DEFAULT_SHORT}</LI> <LI>{@code "int"}: {@link #DEFAULT_INT}</LI> <LI>{@code "long"}: {@link #DEFAULT_LONG}</LI> <LI>{@code "float"}: {@link #DEFAULT_FLOAT}</LI> <LI>{@code "double"}: {@link #DEFAULT_DOUBLE}</LI> <LI><I>anything else</I>: {@code null}</LI> </UL> @see #getForClass(Class) getForClass(cls) **/ public static final Object getForClassName(String s_type) { try { if(s_type.equals("boolean")) { return DEFAULT_BOOLEAN; } } catch(NullPointerException npx) { throw new NullPointerException("getForClassName: s_type"); } if(s_type.equals("char")) { return DEFAULT_CHAR; } if(s_type.equals("byte")) { return DEFAULT_BYTE; } if(s_type.equals("short")) { return DEFAULT_SHORT; } if(s_type.equals("int")) { return DEFAULT_INT; } if(s_type.equals("long")) { return DEFAULT_LONG; } if(s_type.equals("float")) { return DEFAULT_FLOAT; } if(s_type.equals("double")) { return DEFAULT_DOUBLE; } //Non-primitive type return null; } }