web-dev-qa-db-fra.com

Pourquoi Android préfère les classes statiques

Je vois beaucoup de Java où Android préfère que les développeurs utilisent des classes internes statiques. En particulier pour les modèles comme ViewHolder Pattern dans les ListAdapters personnalisés.

Je ne sais pas quelles sont les différences entre les classes statiques et non statiques. J'ai lu à ce sujet, mais cela ne semble pas avoir de sens en ce qui concerne les performances ou l'empreinte mémoire.

39
Jeremy Edwards

Ce n'est pas seulement Android développeurs ...

Une classe interne non statique conserve toujours une référence implicite à l'objet englobant. Si vous n'avez pas besoin de cette référence, elle ne coûte que de la mémoire. Considère ceci:

class Outer {
    class NonStaticInner {}
    static class StaticInner {}
    public List<Object> foo(){ 
        return Arrays.asList(
            new NonStaticInner(),
            new StaticInner()); 
    }
}

Lorsque vous le compilez, vous obtenez quelque chose comme ceci:

class Outer {
    Outer(){}
    public List<Object> foo(){ 
        return Arrays.asList(
            new Outer$NonStaticInner(this),
            new StaticInner()); 
    }
}
class Outer$NonStaticInner {
    private final Outer this$0;
    Outer$NonStaticInner(Outer enclosing) { this$0 = enclosing; }
}
class Outer$StaticInner {
    Outer$StaticInner(){}
}
70
gustafc

La principale différence entre les classes internes statiques et non statiques est qu'une classe interne non statique a accès aux autres membres de la classe externe, même s'ils sont privés. Les classes internes non statiques font "partie" de la classe externe. Vous ne pouvez pas créer ni exister sans une instance d'une classe externe. Une conséquence de cela est qu'une instance d'une classe interne non statique est détruite lorsque l'instance de la classe externe est détruite.

Les classes internes statiques, en revanche, sont exactement comme les classes externes normales. Ils vivent et meurent seuls. Vous n'avez pas besoin d'une instance de la classe externe pour que la classe interne existe. Cela signifie qu'ils ont également leur propre cycle de vie. Ils sont détruits lorsque le ramasseur d'ordures décide de les détruire.

Comment cela affecte-t-il la mémoire et/ou les performances? Je ne sais vraiment pas. :)

26
Jere.Jones

Les classes internes statiques (c'est-à-dire les classes déclarées dans une autre classe avec le mot clé static) sont assez similaires aux classes "normales" sauf que vous ne polluez pas l'espace de nom de votre package. C'est leur (seule) différence et avantage et je pense que c'est la raison pour laquelle vous le voyez dans Android.

Utilisez des classes internes statiques lorsque le but de la classe est restreint à la classe principale, mais ne dépend pas de ses instances. Ceci est généralement considéré comme une bonne pratique.

15
Viliam

Une instance de classe interne non statique contient une référence à l'instance de classe externe, contrairement à une instance de classe interne statique.

Ceci est pertinent pour l'empreinte mémoire des applications car la référence masquée peut entraîner des fuites de mémoire - le garbage collector ne peut pas collecter l'instance de classe externe tant qu'il n'y a plus de références. De plus, la référence supplémentaire elle-même a besoin de mémoire, cela peut être pertinent si un grand nombre d'instances est utilisé.

class Outer{
    class Inner{//Only works with non static inner class
          public Outer getOuter(){return Outer.this;}
    }
}

Il est également pertinent pour son utilisation, la référence à la classe externe est un argument ctor de la classe interne, pour créer un nouvel objet de classe interne non statique, vous devez appeler le ctor comme une fonction membre sur une instance de la classe externe ou à partir de dans une fonction membre de la classe externe. Cela signifie que vous ne pouvez pas avoir une instance de la classe interne sans une instance de la classe externe.

Outer.Inner in = new Outer().new Inner();
7
josefx

Si vous décompilez une classe interne (ou la regardez à l'aide du débogueur), vous pouvez voir qu'il existe du code généré pour accéder à l'instance de la classe externe qui a été utilisée pour les créer. La surcharge pour cela est plus de mémoire pour le pointeur supplémentaire, plus de cpu pour la collecte des ordures à cause du pointeur supplémentaire à tester, et si vous voulez faire un choix, plus de temps de compilation. La création d'instances de classes internes non statiques est un peu plus compliquée car vous avez besoin d'une instance de la classe externe pour les créer.

La visibilité des classes internes statiques et non statiques peut être contrôlée. Habituellement, ils sont privés si leur implémentation est fortement connectée aux détails internes de la classe externe et que le développeur ne pense pas que le code puisse être réutilisé. En ce sens, elles ne valent pas mieux que les fonctions privées. Les classes internes peuvent être publiques dans des cas comme Map.Entry, où la classe interne est fortement connectée à l'interface exposée par la classe, et le développeur ne pense pas que Map.Entry peut être utilisé sans une sorte de carte. Les deux types ont accès aux membres privés de la classe externe et la classe externe a accès aux membres privés de la classe interne.

Les instances de classes internes statiques et non statiques sont récupérées comme toutes les autres classes. Il n'y a pas de connexion spéciale entre la collecte de mémoire de la classe externe et la collecte de mémoire de la classe interne.

Dans le cas de l'implémentation de classes UI comme swing ou Android vous verrez des classes internes statiques car elles sont traitées comme des fonctions privées. Ces classes ne sont pas développées pour être réutilisables en dehors de la classe externe et sont fortement connectées à l'implémentation interne de la classe externe. Il n'y a aucune raison de les exposer et de s'assurer qu'elles peuvent fonctionner dans plus de cas que le contexte spécifique des exigences de la classe externe.

5
shoren