2010-05-23 8 views
46

j'ai un type primitif java à portée de main:Obtenir la valeur par défaut pour les types primitifs Java

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

J'aimerais obtenir une « valeur par défaut » pour cette classe - en particulier la valeur est affectée à des champs de cette tapez s'ils ne sont pas initialisés. Par exemple, '0' pour un nombre, 'faux' pour un booléen.

Existe-t-il une façon générique de faire cela? J'ai essayé

c.newInstance() 

Mais j'obtiens une InstantiationException, et pas une instance par défaut.

+1

Ceci est un problème courant, je souhaite que Java ajoute une fonction 'default (T)' comme C#. – JoeGeeky

+0

C'est à lui seul une question intéressante, mais qu'est-ce que vous en avez besoin après tout? Est-ce pour définir des propriétés de bean ou autre? Ne sont-ils pas déjà implicitement initialisés avec ces valeurs par défaut? – BalusC

+0

@BalusC - Pour initialiser un formulaire HTML qui a un paramètre de méthode avec les valeurs par défaut. – ripper234

Répondre

49

Les bibliothèques Guava contient déjà que:
http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/base/Defaults.html

appel defaultValue retourne la valeur par défaut pour chaque type primitif (tel que spécifié par la JLS), et nulle pour tout autre type.

Utilisez-le comme suit:

import com.google.common.base.Defaults; 
Defaults.defaultValue(Integer.TYPE); //will return 0 
+1

Je voudrais améliorer cette réponse en ajoutant un exemple de ligne de code. Par exemple: 'Defaults.defaultValue (long.class)' Je le dis parce que jusqu'à présent, je n'avais pas réalisé que vous pouviez appeler '.class' sur les types primitifs. – yarian

1

Il n'y a pas une manière élégante de faire ceci. En fait, il n'est même pas possible de déclarer la signature d'une méthode qui retournera les valeurs primitives en soi.

Le plus proche vous pouvez venir est quelque chose comme ceci:

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

La signature est simple: Objet getDefaultValue (Type de classe) – ripper234

+0

Cela ne fonctionnera pas en raison de la valeur de retour. int, long etc ne sont pas 'java.lang.Object's, sauf si vous êtes OK avec le retour des classes wrapper (' java.lang.Integer', 'java.lang.Long' etc). –

+0

@ ripper234 - mais cela retourne des instances wrapper pas des instances des types primitifs. –

2

Vous pouvez le faire avec la réflexion, mais il est plus facile et la plus claire de l'écrire, par exemple

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

Bien sûr, vous voudrez probablement passer l'initialisation de la carte vers un constructeur ou similaire pour l'initialisation une seule fois.

Raisonnablement concis - c'est élégant?

+2

_Vous pouvez le faire avec reflection_ Comment le faites-vous avec la réflexion? –

+0

@mdma Comment cela se ferait-il avec la réflexion? – glen3b

+2

Pourquoi créer une carte si vous ne la réutilisez pas? –

11

C'est ce que je pense (le test échoue élégance bien):

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"); 
     } 
    } 
} 
+0

@PatriceM. Comment iriez-vous avec une variante 'enum' pour cela? –

+0

@Guillaume Polet: Je ne suis pas tout à fait sûr, pour être honnête :-). –

+2

En fait, c'est plutôt joli. Devrait être la réponse acceptée IMO. –

0

Les variables de classe de primitives ne doivent pas nécessairement être initialisé ou défini avec une valeur par défaut. Cependant, les variables déclarées dans une autre portée doivent être initialisées ou vous obtiendrez des erreurs de compilation.

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

}

0

Basé sur Jack Leow's answer, j'ai créé cette classe:

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

Une alternative à ce Defaults.java goyave, qui permet la figure de mise en œuvre les valeurs par défaut (améliorée en utilisant Antag99’s answer):

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 
    } 
} 
+0

Pouvez-vous donner un exemple comment l'utiliser? – MaxZoom

+0

Un peu tard, mais la réflexion n'est-elle pas exagérée dans cette situation? Vous pourriez les mettre vous-même sur la carte pour économiser beaucoup de temps CPU. –

+1

@TadeasKriz - il s'agit juste d'éviter la duplication d'informations; et pas sûr qu'il aurait besoin d'une telle quantité de temps CPU (il est calculé une seule fois). Mais je comprends que cela peut être considéré comme exagéré. –

11

Il est possible d'obtenir la valeur par défaut de n'importe quel type en créant un tableau d'un élément et en récupérant sa première valeur.

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

De cette façon, il n'y a pas besoin de prendre en compte pour chaque type primitif possible, au prix généralement négligeable de la création d'un tableau à un élément.

+0

Élégant, mais pour Array.get: "La valeur est automatiquement enveloppée dans un objet s'il a un type primitif." https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Array.html#get(java.lang.Object,%20int) – LoBo

+0

Clairement la solution la plus élégante. –

+1

@LoBo ce n'est pas un problème; la valeur retournée sera un objet de toute façon. –

Questions connexes