web-dev-qa-db-fra.com

Java: champ statique en classe abstraite

Je commence juste avec un exemple, qui explique le mieux:

public abstract class A{
    static String str;
}

public class B extends A{
    public B(){
        str = "123";
    }
}

public class C extends A{
    public C(){
        str = "abc";
    }
}

public class Main{

    public static void main(String[] args){
        A b = new B();
        A c = new C();
        System.out.println("b.str = " + b.str);
        System.out.println("c.str = " + c.str);
    }
}

Cela va imprimer:

b.str = abc

c.str = abc

Mais je voudrais une solution où chaque sous-classe qui instancie la super classe a sa variable own class, en même temps, je veux pouvoir référencer cette variable de classe via l’identifiant, ou un appel de méthode, défini dans la super classe abstraite.

Je voudrais donc que le résultat soit: 

b.str = 123 

c.str = abc

Est-ce faisable? 

42
Tommy

Si vous voulez que les classes B et C aient des variables statiques distinctes, vous devez déclarer les variables dans ces classes. Fondamentalement, les membres statiques et le polymorphisme ne vont pas ensemble.

Notez que l'accès aux membres statiques via des références est une vraiment mauvaise idée en termes de lisibilité - cela donne à look l'impression que cela dépend de la valeur de la référence, alors que ce n'est pas le cas. Ainsi, votre code actuel ne sera même pas compilé lorsque vous aurez déplacé str vers B et C. Au lieu de cela, vous aurez besoin de

System.out.println("b.str = " + B.str);
System.out.println("c.str = " + C.str);

Si vous devez vraiment accéder à la valeur de manière polymorphe (c'est-à-dire via une instance de A), une option consiste à créer un getter polymorphe:

public class A {
    public abstract String getStr();
}

public class B extends A {
    private static String str = "b";

    @Override public String getStr() {
        return str;
    }
}

(et le même pour C).

De cette façon, vous obtenez le comportement souhaité en ce qui concerne le fait de ne pas avoir une variable variable distincte par instance, mais vous pouvez toujours l'utiliser de manière polymorphe. Il est un peu étrange pour un membre d'instance de renvoyer une valeur statique comme celle-ci, mais vous utilisez la valeur du polymorphisme de type, en gros ...

46
Jon Skeet
public abstract class A {
    private String str;
    public String getStr() { return str;}
    protected void setStr(String str) { this.str = str; }
}

Ensuite, vous pourrez avoir

B b = new B();
b.getStr();

Le setter et le getter sont mon ajout, vous pouvez y aller simplement en rendant la variable non statique.

Update Si vous voulez avoir le static-per-subclass, alors vous pouvez avoir:

protected static Map<Class, String> values;
public abstract String getValue();

et alors:

public String getValue() {
    values.get(getClass());
}
public void setValue(String value) {
    values.set(getClass(), value);
}

Mais c'est généralement une mauvaise idée.

6
Bozho

Mettez la varibale statique dans chaque sous-classe et ajoutez une méthode abstraite (non statique) à la superclasse abstraite:

abstract String getStr();

Puis implémentez la méthode getStr () dans chaque sous-classe en renvoyant le champ statique de cette sous-classe spéciale.

public class B extends A {
 private static String str;

  @Override
  public String getStr() {
    return B.str;
  }
}
3
Ralph

Puisque vous codifiez de toute façon la valeur ou la str dans les sous-classes, vous pouvez faire quelque chose comme ceci:

public abstract class A{
    public abstract String getStr();
}

public class B extends A{
   public String getStr(){
      return "123";
   }
}

public class C extends A{
   public String getStr(){
      return "abc";
   }
}

Cela ferait l'affaire dans votre cas.

Bien sûr, alors vous devriez l'appeler par méthode, comme ceci:

public class Main{

    public static void main(String[] args){
        A b = new B();
        A c = new C();
        System.out.println("b.str = " + b.getStr());
        System.out.println("c.str = " + c.getStr());
    }
}
2
Goran Jovic

une seule instance de variable statique est présente dans le système.

la variable statique se chargera dans le système au début avant que la classe ne soit chargée.

la raison pour laquelle le temps abc est imprimé est due au fait que vous définissez la valeur de str comme étant abc dans le dernier.

2
Chirag Tayal

Ceci imprimera le résultat souhaité:

public abstract class A{
}

public class B extends A{
    static String str;

    public B(){
        str = "123";
    }
}

public class C extends A{
    static String str;

    public C(){
        str = "abc";
    }
}

public class Main{

    public static void main(String[] args){
        A a = new B();
        A c = new C();
        System.out.println("B.str = " + B.str);
        System.out.println("C.str = " + C.str);
    }
}
2
Thijs Wouters

C'est ce que j'ai fait pour éviter de devoir implémenter la même méthode dans chaque sous-classe. Il est basé sur la réponse de Bozho. Peut-être que cela peut aider quelqu'un.

import Java.util.HashMap;
import Java.util.Map;

/**
 *
 * @author Uglylab
 */
public class SandBox {

    public static void main(String[] args) {
        A b = new B();
        A c = new C();
        System.out.println("b.str = " + B.getStr(b.getClass()));
        System.out.println("c.str = " + C.getStr(c.getClass()));
    }

}
 abstract class A{
    protected static Map<Class, String> values = new HashMap<>();


    public static String getStr(Class<? extends A> aClass) {
        return values.get(aClass);
    }

    public static void setStr(Class<? extends A> aClass, String s) {
        values.put(aClass, s);
    }

}

 class B extends A{
    public B(){
        setStr(this.getClass(),"123");
    }
}

 class C extends A{
    public C(){
        setStr(this.getClass(),"abc");
    }
}
1
Uglylab

Je pense qu'une solution consiste à utiliser un singleton pour les classes B et C pour imiter les méthodes et les champs statiques. Les deux peuvent étendre la classe abstraite A, mais auront leurs propres valeurs de str ..

0
Martin Konecny