3 votes

Une reliure tardive ? Champ ou propriété. Self ou Static

Cela me préoccupe depuis longtemps, alors j'ai pensé que je devais le demander.

Si j'écris

import java.util.*;
import java.lang.*;

class Main
{
    public static void main (String[] args) throws java.lang.Exception
    {
            new Shape();
            new Triangle();
    }

    public static class Shape
    {
            static String name = "shape";

            Shape()
            {
                    printName();
            }

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

            public String name()
            {
                    return name;
            }
    }

    public static class Triangle extends Shape
    {
            static String name = "triangle";

            public String name()
            {
                    return name;
            }
    }
}

alors la sortie est

shape
triangle

Mais si j'écris

import java.util.*;
import java.lang.*;

class Main
{
    public static void main (String[] args) throws java.lang.Exception
    {
            new Shape();
            new Triangle();
    }

    public static class Shape
    {
            static String name = "shape";

            Shape()
            {
                    printName();
            }

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

    }

    public static class Triangle extends Shape
    {
            static String name = "triangle";
    }
}

alors la sortie est

shape
shape

Dans la première version, je dois copier/coller la même fonction getName() dans chaque sous-classe. Il doit y avoir un meilleur moyen. Que dois-je changer dans le deuxième exemple ?

5voto

Andremoniy Points 7349

Les champs statiques ne sont pas accessibles depuis les classes parentes. La classe Shape ne "voit" pas le champ statique name de la classe Triangle et utilise son propre champ statique name .

UPD : Vous demandez : que devez-vous changer dans le deuxième exemple ? Plus précisément, votre premier exemple est une "correction" correcte de votre deuxième exemple. La seule manière correcte est d'utiliser une méthode getter comme votre name() méthode.

UPD2 : (d'après mon commentaire) : Eh bien, une autre façon : pardonner à propos de n'importe quel type de champ name . Utilisez plutôt une méthode appelée name() (pas statique !) qui retournera dans chaque classe le nom nécessaire. Il suffit de return "shape"; o return "triangle" en eux ;

1voto

Andremoniy Points 7349

Eh bien, j'ai déjà répondu à cette question de manière négative. Mais comme une sorte de blague et de solution amusante ( ce qui va marcher ! !! ), vous pourriez modifier votre printName() à celle-ci :

public void printName() throws NoSuchFieldException, IllegalAccessException {
    System.out.println((String)(this.getClass().getDeclaredField("name").get(this)));
}

Il ne s'agit que d'une seule modification, que vous devez effectuer dans l'onglet deuxième exemple pour obtenir la sortie

shape
triangle

0voto

Tom Anderson Points 22456

C'est une excellente illustration de la manière dont Java résout les noms en valeurs. Vous avez deux variables appelées name un en Shape et un en Triangle . Même si Triangle est une sous-classe de Shape ce sont des variables totalement indépendantes . C'est parce qu'ils sont statiques ; les choses statiques ne sont jamais surchargées, car elles appartiennent à la classe, pas à l'objet. Sur Shape quand vous faites référence à name c'est en fait un raccourci pour Shape.name . De même, en Triangle , name signifie Triangle.name . Le site même symbole se réfère à différentes variables en différents champs d'application .

Dans ce code :

public class Shape {
    static String name = "shape";

    public static void main(String[] args) {
        System.out.println(name);
    }
}

class Colour {
    static String name = "colour";
}

Vous ne penseriez pas une seconde que la sortie serait "couleur", n'est-ce pas ? C'est exactement la situation dans le code que vous montrez. La relation d'héritage entre les deux classes n'est qu'un faux-fuyant.

Si vous voulez que le nom soit polymorphe, votre seule option est d'utiliser une méthode d'instance, car les méthodes d'instance sont les seuls éléments qui peuvent être polymorphes. La façon la plus concise de le faire est d'intégrer les constantes dans les méthodes :

class Main {

    public static void main(String[] args) {
        new Shape();
        new Triangle();
    }

    public static class Shape {
        Shape() {
            printName();
        }

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

        public String name() {
            return "shape";
        }
    }

    public static class Triangle extends Shape {
        @Override
        public String name() {
            return "triangle";
        }
    }
}

0voto

DiddiZ Points 159

Vous pourriez utiliser un champ final et le définir dans le constructeur, mais je pense qu'il est préférable de remplacer les récupérateurs.

public static class Shape
{
        protected final String name;

        public Shape()
        {
                this("shape");
        }

        protected Shape(String name)
        {
                this.name = name;
        }

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

        public String name()
        {
                return name;
        }
}

public static class Triangle extends Shape
{
        public Triangle()
        {
               super("triangle");
        }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X