Est-il un moyen de remplacer les variables de classe en Java?


class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String me = "son";
}

public void doIt()
{
    new Son().printMe();
}

La fonction doIt imprimer "papa". Est-il un moyen de le faire imprimer "fils"?

Author: James P., 2009-03-26

16 answers

Oui. Mais comme la variable est concernée, elle est écrasée (donnant une nouvelle valeur à la variable. Donner une nouvelle définition à la fonction est Override).Just don't declare the variable but initialize (change) in the constructor or static block.

La valeur sera reflétée lors de l'utilisation dans les blocs de la classe parent

Si la variable est statique, modifiez la valeur lors de l'initialisation elle-même avec static block,

class Son extends Dad {
    static { 
       me = 'son'; 
    }
}

Ou bien changement dans le constructeur.

Vous pouvez également modifier la valeur ultérieurement dans n'importe quel bloc. Cela se reflétera dans la super classe

 48
Author: Vivek MVK, 2016-06-30 06:41:01

En bref, non, il n'y a aucun moyen de remplacer une variable de classe.

Vous ne remplacez pas les variables de classe en Java, vous les masquez. Le remplacement est par exemple des méthodes. Cacher est différent de remplacer.

Dans l'exemple que vous avez donné, en déclarant la variable de classe avec le nom 'me' dans class Son, vous masquez la variable de classe qu'elle aurait héritée de son père de superclasse avec le même nom 'me'. Masquer une variable de cette manière n'affecte pas la valeur de la variable de classe "moi" dans la superclasse Papa.

Pour la deuxième partie de votre question, sur la façon de le faire imprimer "son", je définirais la valeur via le constructeur. Bien que le code ci-dessous s'écarte beaucoup de votre question d'origine, je l'écrirais quelque chose comme ceci;

public class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public void printName() {
        System.out.println(name);
    }
}

Le JLS donne beaucoup plus de détails sur le masquage dans la section 8.3-Déclarations de champ

 91
Author: Mike, 2013-04-19 19:24:50

Oui, il suffit de remplacer la méthode printMe():

class Son extends Dad {
        public static final String me = "son";

        @Override
        public void printMe() {
                System.out.println(me);
        }
}
 31
Author: romaintaz, 2014-05-12 06:35:03

Vous pouvez créer un getter, puis remplacer ce getter. C'est particulièrement utile si la variable que vous remplacez est une sous-classe d'elle-même. Imaginez que votre super classe a un membre Object mais dans votre sous-classe, cela est maintenant plus défini pour être un Integer.

class Dad
{
        private static final String me = "dad";

        protected String getMe() {
            return me;
        }

        public void printMe()
        {
                System.out.println(getMe());
        }
}

class Son extends Dad
{
        private static final String me = "son";

        @Override
        protected String getMe() {
            return me;
        }
}

public void doIt()
{
        new Son().printMe(); //Prints "son"
}
 15
Author: John Strickler, 2011-12-27 18:25:03

Si vous allez le remplacer, je ne vois pas de raison valable de garder cela statique. Je suggérerais l'utilisation de l'abstraction (voir exemple de code). :

     public interface Person {
        public abstract String getName();
       //this will be different for each person, so no need to make it concrete
        public abstract void setName(String name);
    }

Maintenant, nous pouvons ajouter le Papa:

public class Dad implements Person {

    private String name;

    public Dad(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
    return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}

Le fils:

public class Son implements Person {

    private String name;

    public Son(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
        return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}

Et Papa a rencontré une gentille dame:

public class StepMom implements Person {

    private String name;

    public StepMom(String name) {
        setName(name);
    }

    @Override
    public final String getName() {
        return name;
    }

    @Override
    public final void setName(String name) {
        this.name = name;
    }
}

On dirait que nous avons une famille, disons au monde leurs noms:

public class ConsoleGUI {

    public static void main(String[] args) {
        List<Person> family = new ArrayList<Person>();
        family.add(new Son("Tommy"));
        family.add(new StepMom("Nancy"));
        family.add(new Dad("Dad"));
        for (Person person : family) {
            //using the getName vs printName lets the caller, in this case the
            //ConsoleGUI determine versus being forced to output through the console. 
            System.out.print(person.getName() + " ");
            System.err.print(person.getName() + " ");
            JOptionPane.showMessageDialog(null, person.getName());
    }
}

}

Système.sortie: Tommy Nancy Papa
Système.err est le même que ci-dessus (a juste la police rouge)
Sortie JOption:
Tommy , puis
Nancy , puis
Papa

 10
Author: nckbrz, 2016-05-02 13:27:28

Cela ressemble à un défaut de conception.

Supprimez le mot-clé static et définissez la variable par exemple dans le constructeur. De cette façon, Son définit simplement la variable à une valeur différente dans son constructeur.

 6
Author: Patrick Cornelissen, 2009-03-26 11:17:14

Bien qu'il soit vrai que les variables de classe ne peuvent être cachées que dans les sous-classes, et non remplacées, il est toujours possible de faire ce que vous voulez sans remplacer printMe () dans les sous-classes, et la réflexion est votre amie. Dans le code ci-dessous, j'omets la gestion des exceptions pour plus de clarté. Veuillez noter que déclarer me comme protected ne semble pas avoir beaucoup de sens dans ce contexte, car il va être caché dans les sous-classes...

class Dad
  {
    static String me = "dad";

    public void printMe ()
      {
        java.lang.reflect.Field field = this.getClass ().getDeclaredField ("me");
        System.out.println (field.get (null));
      }
  }
 4
Author: Sergey Ushakov, 2013-07-21 16:28:24
class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String _me = me = "son";
}

public void doIt()
{
    new Son().printMe();
}

... imprimé "fils".

 3
Author: user2895864, 2013-10-18 17:53:51

Seulement en remplaçant printMe():

class Son extends Dad 
{
    public void printMe() 
    {
        System.out.println("son");
    }
}

La référence à me dans la méthode Dad.printMe pointe implicitement vers le champ statique Dad.me, donc d'une manière ou d'une autre, vous changez ce que printMe fait dans Son...

 2
Author: Dan Vinton, 2009-03-26 11:10:49

Vous ne pouvez pas remplacer les variables dans une classe. Vous pouvez remplacer uniquement les méthodes. Vous devez garder les variables privées sinon vous pouvez avoir beaucoup de problèmes.

 2
Author: Ionel Bratianu, 2009-03-26 11:19:56

Il imprime en effet "papa", car le champ n'est pas surchargé mais caché. Il existe trois approches pour lui faire imprimer 'son':

Approche 1: remplacer PrintMe

class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String me = "son";

    @override
    public void printMe()
    {
        System.out.println(me);
    }
}

public void doIt()
{
    new Son().printMe();
}

Approche 2: ne cachez pas le champ et initialisez-le dans le constructeur

class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    public Son()
    {
        me = "son";
    }
}

public void doIt()
{
    new Son().printMe();
}

Approche 3: utilisez la valeur statique pour initialiser un champ dans le constructeur

class Dad
{
    private static String meInit = "Dad";

    protected String me;

    public Dad() 
    {
       me = meInit;
    }

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    private static String meInit = "son";

    public Son()
    {
        me = meInit;
    }

}

public void doIt()
{
    new Son().printMe();
}
 2
Author: Rik Schaaf, 2015-04-17 03:16:39

Https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html

C'est ce qu'on appelle Masquer les champs

à Partir du lien ci-dessus

Dans une classe, un champ qui porte le même nom qu'un champ de la superclasse masque le champ de la superclasse, même si leurs types sont différents. Dans la sous-classe, le champ de la superclasse ne peut pas être référencé par son nom simple. Au lieu de cela, le champ doit être accessible via super, qui est couvert dans la prochaine section. De manière générale, nous ne recommandons pas de masquer les champs car cela rend le code difficile à lire.

 2
Author: sadjkas sadal, 2017-04-24 04:19:07

Bien sûr, utiliser des attributs privés, et des getters et des setters serait la chose recommandée à faire, mais j'ai testé ce qui suit, et cela fonctionne... Voir le commentaire dans le code

class Dad
{
    protected static String me = "dad";

    public void printMe()
    {
        System.out.println(me);
    }
}

class Son extends Dad
{
    protected static String me = "son";

    /* 
    Adding Method printMe() to this class, outputs son 
    even though Attribute me from class Dad can apparently not be overridden
    */

    public void printMe()
    {
        System.out.println(me);
    }
}

class Tester
{
    public static void main(String[] arg)
    {
        new Son().printMe();
    }
}

Sooo ... est-ce que je viens de redéfinir les règles d'héritage ou ai-je mis Oracle dans une situation délicate ? Pour moi, la chaîne statique protégée me est clairement remplacée, comme vous pouvez le voir lorsque vous exécutez ce programme. En outre, cela n'a aucun sens pour moi pourquoi les attributs ne devraient pas être remplaçables.

 0
Author: Pixel, 2012-07-17 12:46:06

Pourquoi voudriez-vous remplacer les variables alors que vous pourriez facilement les réaffecter dans les sous-classes.

Je suis ce modèle pour travailler autour de la conception du langage. Supposons un cas où vous avez une classe de service importante dans votre framework qui doit être utilisée dans différentes saveurs dans plusieurs dérivés applications.In dans ce cas, la meilleure façon de configurer la logique de la super classe est de réaffecter ses variables "définissant".

public interface ExtensibleService{
void init();
}

public class WeightyLogicService implements ExtensibleService{
    private String directoryPath="c:\hello";

    public void doLogic(){
         //never forget to call init() before invocation or build safeguards
         init();
       //some logic goes here
   }

   public void init(){}    

}

public class WeightyLogicService_myAdaptation extends WeightyLogicService {
   @Override
   public void init(){
    directoryPath="c:\my_hello";
   }

}
 0
Author: premganz, 2015-06-11 10:11:04

Non. Les variables de classe (également applicables aux variables d'instance) n'affichent pas de fonctionnalité de substitution en Java car les variables de classe sont invoquées sur la base du type d'objet appelant. Ajout d'une classe supplémentaire(Humaine) dans la hiérarchie pour le rendre plus clair. Alors maintenant nous avons

Fils étend Papa étend humain

Dans le code ci-dessous, nous essayons d'itérer sur un tableau d'objets Humains, Père et Fils, mais il imprime les valeurs de la classe humaine dans tous les cas comme l'était le type d'objet appelant Humain.

    class Human
{
    static String me = "human";

    public void printMe()
    {
        System.out.println(me);
    }
}
class Dad extends Human
{
    static String me = "dad";

}

class Son extends Dad
{
    static String me = "son";
}


public class ClassVariables {
    public static void main(String[] abc)   {
        Human[] humans = new Human[3];
        humans[0] = new Human();
        humans[1] = new Dad();
        humans[2] = new Son();
        for(Human human: humans)   {
            System.out.println(human.me);        // prints human for all objects
        }
    }
}

Imprimera

  • humain
  • humain
  • humain

Donc pas de remplacement des variables de classe.

Si nous voulons accéder à la variable de classe de l'objet réel à partir d'une variable de référence de sa classe parente, nous devons le dire explicitement au compilateur en convertissant la référence parent (objet humain) en son type.

    System.out.println(((Dad)humans[1]).me);        // prints dad

    System.out.println(((Son)humans[2]).me);        // prints son

Imprimera

  • papa
  • fils

Sur la façon dont une partie de ce question: - Comme déjà suggéré remplacer la méthode PrintMe () dans la classe Son, puis en appelant

Son().printMe();

La variable de classe de papa "me" sera masquée car la déclaration la plus proche(de la méthode printme() de la classe Son) du "me"(dans la classe Son) obtiendra la priorité.

 0
Author: Developer, 2018-05-05 16:21:18

Les variables ne participent pas au dépassement. Seules les méthodes le font. Un appel de la méthode est résolu au moment de l'exécution, qui est, la décision d'appeler une méthode est prise au moment de l'exécution, mais les variables sont décidées au moment de la compilation seulement. Par conséquent, cette variable est appelée dont la référence est utilisée pour l'appel et non de l'objet d'exécution.

Jetez un oeil à l'extrait suivant:

package com.demo;

class Bike {
  int max_speed = 90;
  public void disp_speed() {
    System.out.println("Inside bike");
 }
}

public class Honda_bikes extends Bike {
  int max_speed = 150;
  public void disp_speed() {
    System.out.println("Inside Honda");
}

public static void main(String[] args) {
    Honda_bikes obj1 = new Honda_bikes();
    Bike obj2 = new Honda_bikes();
    Bike obj3 = new Bike();

    obj1.disp_speed();
    obj2.disp_speed();
    obj3.disp_speed();

    System.out.println("Max_Speed = " + obj1.max_speed);
    System.out.println("Max_Speed = " + obj2.max_speed);
    System.out.println("Max_Speed = " + obj3.max_speed);
  }

}

Lorsque vous exécutez le code, la console affichera:

Inside Honda
Inside Honda
Inside bike

Max_Speed = 150
Max_Speed = 90
Max_Speed = 90
 0
Author: Ananta S E, 2018-09-11 16:58:13