Java 获取基元类型的默认值

Java 获取基元类型的默认值,java,reflection,guava,Java,Reflection,Guava,我手头有一个Java原语类型: Class<?> c = int.class; // or long.class, or boolean.class 但是我得到的是一个实例化异常,而不是一个默认实例。没有一种优雅的方法可以做到这一点。事实上,甚至不可能声明将返回原语值本身的方法的签名 你能到达的最近点是这样的: public Object defaultValue(Class cls) { if (class == Boolean.TYPE) { retur

我手头有一个Java原语类型:

Class<?> c = int.class; // or long.class, or boolean.class

但是我得到的是一个
实例化异常
,而不是一个默认实例。

没有一种优雅的方法可以做到这一点。事实上,甚至不可能声明将返回原语值本身的方法的签名

你能到达的最近点是这样的:

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;
    }
}

你可以通过反射来实现这一点,但写出来是最简单、最清晰的

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 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();
}

}番石榴图书馆已经包含了:

调用
defaultValue
将返回任何基元类型(由JLS指定)的默认值,并为任何其他类型返回null

像这样使用它:

import com.google.common.base.Defaults;
Defaults.defaultValue(Integer.TYPE); //will return 0
基于,我创建了这个类:

/**
   <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> &nbsp; &nbsp; {@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;
   }
}

Guava的
Defaults.java
的替代方案,它让实现计算出默认值(通过使用改进):


通过创建一个元素数组并检索其第一个值,可以获得任何类型的默认值

private static <T> T getDefaultValue(Class<T> clazz) {
    return (T) Array.get(Array.newInstance(clazz, 1), 0);
}
private static T getDefaultValue(类clazz){
return(T)Array.get(Array.newInstance(clazz,1),0);
}

这样,就不需要考虑每种可能的基元类型,而创建一个元素数组的成本通常可以忽略不计。

如果您想要包括字符串数据类型在内的默认值,请尝试以下方法:

private static Object getDefaultValue(Field field) {
        if (Number.class.isAssignableFrom(field.getType())) {
            if (Double.class.isAssignableFrom(field.getType())
                || Float.class.isAssignableFrom(field.getType())) {
                return 0.0;
            } else {
                return 0;
            }
        } else if (Boolean.class.isAssignableFrom(field.getType())) {
            return false;
        } else if (Timestamp.class.isAssignableFrom(field.getType())) {
            return new Timestamp(Instant.now().toEpochMilli());
        } else {
            return "NULL";
        }
    }


签名很简单:对象getDefaultValue(类类型),因为返回值而无法工作。int、long等不是
java.lang.Object
s,除非您可以返回包装类(
java.lang.Integer
java.lang.long
等)。@ripper234-但这会返回包装实例,而不是基元类型的实例。事实上,您可以这样声明上述方法的签名:
publicstatict defaultValue(Class cls)
我可以返回包装器类。这是一个常见的问题,我希望Java能够添加一个类似C#的
default(T)
函数。这本身就是一个有趣的问题,但您到底需要它做什么?是设置一些bean属性吗?它们不是已经用这些默认值隐式初始化了吗?@BalusC-初始化一个具有默认值的方法参数的HTML表单。可以用反射来实现这一点。如何用反射来实现?如果不重用映射,为什么要创建映射?@PatriceM。对于这个问题,你会如何使用
enum
变体?@Guillaume Polet:老实说,我不太确定:-)。实际上这是非常简洁的。应该是IMO接受的答案。我将通过添加示例代码行来改进此答案。例如:
Defaults.defaultValue(long.class)
我这样说是因为直到现在我才意识到可以对基元类型调用
.class
。如何将其与类泛型类型参数
一起使用?泛型类型从来都不是基元,因此默认值总是空的。你能提供一些如何使用它的示例吗?有点晚了,但是,在这种情况下,反思难道不是一种过度的杀伤力吗?可以自己把它们放到地图上以节省大量的CPU时间。@TadeasKriz-这只是为了避免重复信息;而且不确定它是否需要如此大量的CPU时间(只计算一次)。但我知道这可能被认为是过度杀戮。优雅,但对于Array.get:“如果对象具有基元类型,则值会自动包装在对象中。”显然,这是最优雅的解决方案。@LoBo这不是问题;返回的值无论如何都将是一个对象。
Array.get(Array.newInstance(Boolean.class,1),0)
返回null:(@AquariusPower Boolean不是一个基本类;
Array.get(Array.newInstance(Boolean.class,1),0)
返回false(作为包装布尔对象)。
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
    }
}
private static <T> T getDefaultValue(Class<T> clazz) {
    return (T) Array.get(Array.newInstance(clazz, 1), 0);
}
private static Object getDefaultValue(Field field) {
        if (Number.class.isAssignableFrom(field.getType())) {
            if (Double.class.isAssignableFrom(field.getType())
                || Float.class.isAssignableFrom(field.getType())) {
                return 0.0;
            } else {
                return 0;
            }
        } else if (Boolean.class.isAssignableFrom(field.getType())) {
            return false;
        } else if (Timestamp.class.isAssignableFrom(field.getType())) {
            return new Timestamp(Instant.now().toEpochMilli());
        } else {
            return "NULL";
        }
    }