web-dev-qa-db-fra.com

Comment forcer une classe à être initialisée?

Quelle est la meilleure et la plus propre façon de procéder? Plus précisément, j'ai besoin de code dans un bloc d'initialisation statique pour s'exécuter dans cette classe, mais j'aimerais le rendre aussi propre que possible.

37
Artem

Chargement! = Initialisation.

Vous voulez que votre classe soit initialisée (c'est entre autres lors de l'exécution de blocs statiques).

Un extrait de la Spécification du langage Java dit:

Une classe ou une interface de type T sera initialisée immédiatement avant la première occurrence de> l'un des suivants:

  • T est une classe et une instance de T est créée.
  • T est une classe et une méthode statique déclarée par T est appelée.
  • Un champ statique déclaré par T est affecté.
  • Un champ statique déclaré par T est utilisé et le champ n'est pas une variable constante (§4.12.4).
  • T est une classe de niveau supérieur et une instruction assert (§14.10) imbriquée lexicalement dans T est exécutée. 

L'invocation de certaines méthodes de réflexion dans la classe Class et dans le package Java.lang.reflect entraîne également l'initialisation de la classe ou de l'interface. Une classe ou une interface ne sera initialisée dans aucune autre circonstance.

Doh, anovstrup, l'a déjà dit: Créez une fonction statique vide appelée init. Assurez-vous de documenter aussi bien ... Personnellement, je ne vois cependant aucun cas d'utilisation pour cela dans le contexte d'un code bien formé.

Vous pouvez utiliser le code suivant pour forcer l'initialisation d'une classe:

//... Foo.class ...          //OLD CODE
... forceInit(Foo.class) ... //NEW CODE

/**
 * Forces the initialization of the class pertaining to 
 * the specified <tt>Class</tt> object. 
 * This method does nothing if the class is already
 * initialized prior to invocation.
 *
 * @param klass the class for which to force initialization
 * @return <tt>klass</tt>

 */
public static <T> Class<T> forceInit(Class<T> klass) {
    try {
        Class.forName(klass.getName(), true, klass.getClassLoader());
    } catch (ClassNotFoundException e) {
        throw new AssertionError(e);  // Can't happen
    }
    return klass;
} 
11
Iulian
try
{
  Class.forName(class name as string)
}
catch(ClassNotFoundException e)
{
  whatever
}

Ça devrait le faire.

@ Longpoke

Peut-être que je ne comprends pas quelque chose alors. Pouvez-vous créer un exemple dans lequel une classe est chargée mais l'initialiseur statique est pas exécuté? Voici un exemple qui ne fait qu'imprimer ce qu'il a chargé:

package test;

public class TestStatic 
{
    public static void main(String[] args) 
    {
        try 
        {
            Class.forName("test.Static");
        }
        catch (ClassNotFoundException e) 
        {
            e.printStackTrace();
        }
    }
}

Avec la classe statique suivante en cours de chargement:

package test;

public class Static 
{
    static
    {
        System.out.println("Static Initializer ran...");
    }
}

Si les initialiseurs statiques ne sont pas exécutés tant que les conditions que vous avez énumérées ne sont pas remplies, pourquoi cette impression est-elle exécutée lorsque je lance mon test? C’est laquelle des conditions énumérées que je rencontre?

7
BigMac66

Les dépendances invisibles entre les classes ne sont pas une bonne idée. Je suggère de déplacer le code du bloc initializer statique vers une méthode statique et de l'appeler directement dans la classe dépendante. Le bloc d'initialisation statique peut être réécrit pour appeler la méthode statique nouvellement créée.

4
Abhinav Sarkar

Une solution serait d'appeler une méthode statique:

public class A {
   static { DebugUtils.FLAG_TEST_USER = true; }

   static void init() {}
}

Ensuite, appelez A.init() pour forcer l'initialisation.

Cependant, cela fait du tout une odeur de code. Pensez à remplacer votre code statique par un constructeur standard dans un objet singleton.

1
Aaron Novstrup

Si vous devez lancer statiquement quelque chose dans une classe, cela signifie qu'il doit y avoir des classes clientes dépendantes de cela. 

S'il y a un client, ou appelons-le une maison naturelle pour le bloc d'initialisation, je pense qu'il serait plus propre de l'initialiser ici.

Pour le cas de nombreux clients égaux, il peut être judicieux de vérifier à partir de ces classes que l'initialisation statique dans l'autre classe a réussi. Ensuite, le couplage est documenté et vous êtes sûr que la classe est toujours initialisée avant que le premier client en ait besoin.

0
Peter Tillemans