it-swarm.com.de

Gibt es eine Möglichkeit, Klassenvariablen in Java zu überschreiben?

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();
}

Die Funktion doIt druckt "Papa". Gibt es eine Möglichkeit, "Sohn" drucken zu lassen?

140
Dikla

Ja. Aber da es sich um die Variable handelt, wird sie überschrieben (Neue Variable für die Variable. Die neue Definition für die Funktion ist Override) .Just don't declare the variable but initialize (change) in the constructor or static block.

Der Wert wird reflektiert, wenn er in den Blöcken der übergeordneten Klasse verwendet wird

wenn die Variable statisch ist, ändern Sie den Wert während der Initialisierung selbst mit dem statischen Block.

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

oder sonst im Konstruktor ändern.

Sie können den Wert auch später in beliebigen Blöcken ändern. Es wird in der Superklasse reflektiert

52
Vivek MVK

Kurz gesagt, nein, es gibt keine Möglichkeit, eine Klassenvariable zu überschreiben. 

Sie überschreiben Klassenvariablen in Java nicht, Sie blenden sie aus. Das Überschreiben betrifft beispielsweise Methoden. Das Ausblenden unterscheidet sich vom Überschreiben. 

In dem Beispiel, das Sie gegeben haben, verbergen Sie durch Deklarieren der Klassenvariablen mit dem Namen "me" in der Klasse Son die Klassenvariable, die sie von ihrer übergeordneten Klasse Dad mit dem gleichen Namen "me" geerbt hätte. Das Ausblenden einer Variablen auf diese Weise wirkt sich nicht auf den Wert der Klassenvariablen 'me' im übergeordneten Dad aus.

Für den zweiten Teil Ihrer Frage, wie "Sohn" gedruckt werden soll, würde ich den Wert über den Konstruktor einstellen. Obwohl der unten stehende Code von Ihrer ursprünglichen Frage sehr abweicht, würde ich so etwas schreiben.

public class Person {
    private String name;

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

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

Das JLS enthält mehr Details zum Verstecken in Abschnitt 8.3 - Felddeklarationen

91
Mike

Ja, überschreiben Sie einfach die printMe()-Methode:

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

        @Override
        public void printMe() {
                System.out.println(me);
        }
}
31
Romain Linsolas

Sie können einen Getter erstellen und diesen Getter dann überschreiben. Dies ist besonders nützlich, wenn die Variable, die Sie überschreiben, eine Unterklasse von sich selbst ist. Stellen Sie sich vor, Ihre Superklasse hat ein Object-Mitglied, aber in Ihrer Unterklasse ist diese jetzt mehr als Integer definiert.

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
John Strickler

Wenn Sie es außer Kraft setzen, sehe ich keinen triftigen Grund, um diese Statik zu behalten. Ich würde die Verwendung von Abstraktion vorschlagen (siehe Beispielcode). : 

     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);
    }

Jetzt können wir den Vater hinzufügen:

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;
    }
}

der Sohn:

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;
    }
}

und Papa traf eine nette 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;
    }
}

Sieht aus wie wir eine Familie haben, sagen wir der Welt ihre Namen:

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());
    }
}

}

System.out Ausgabe: Tommy Nancy Dad
System.err ist das gleiche wie oben (hat nur rote Schrift)
JOption-Ausgabe:
Tommy dann  
Nancy dann  
Papa

10
nckbrz

Das sieht nach einem Designfehler aus.

Entfernen Sie das statische Schlüsselwort und legen Sie die Variable beispielsweise im Konstruktor fest. Auf diese Weise setzt Son die Variable in seinem Konstruktor auf einen anderen Wert.

6

Es ist zwar richtig, dass Klassenvariablen nur in Unterklassen versteckt und nicht überschrieben werden dürfen, Sie können jedoch das tun, was Sie möchten, ohne printMe () in Unterklassen zu überschreiben. Im folgenden Code lasse ich die Ausnahmebehandlung aus Gründen der Übersichtlichkeit weg. Beachten Sie, dass die Deklaration von me als protected in diesem Zusammenhang nicht viel Sinn zu haben scheint, da sie in Unterklassen versteckt wird ...

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
Sergey Ushakov
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();
}

... wird "Sohn" drucken.

3
user2895864

nur durch Überschreiben von printMe():

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

der Verweis auf me in der Dad.printMe-Methode verweist implizit auf das statische Feld Dad.me. Auf diese Weise ändern Sie, was printMe in Son... tut.

2
Dan Vinton

Sie können Variablen in einer Klasse nicht überschreiben. Sie können nur Methoden überschreiben. Sie sollten die Variablen privat halten, ansonsten können Sie viele Probleme bekommen.

2
Ionel Bratianu

In der Tat wird "Papa" gedruckt, da das Feld nicht überschrieben, sondern versteckt wird. Es gibt drei Ansätze, um "Sohn" zu drucken:

Ansatz 1: printMe überschreiben

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();
}

Ansatz 2: Blenden Sie das Feld nicht aus und initialisieren Sie es im Konstruktor

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();
}

Ansatz 3: Verwenden Sie den statischen Wert, um ein Feld im Konstruktor zu initialisieren

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
Rik Schaaf

https://docs.Oracle.com/javase/tutorial/Java/IandI/hidevariables.html

Es heißt Hiding Fields

Über den Link oben

Innerhalb einer Klasse blendet ein Feld, das denselben Namen wie ein Feld in der Superklasse hat, das Feld der Superklasse aus, selbst wenn ihre Typen unterschiedlich sind. Innerhalb der Unterklasse kann das Feld in der Oberklasse nicht mit seinem einfachen Namen referenziert werden. Stattdessen muss auf das Feld über super zugegriffen werden, was im nächsten Abschnitt behandelt wird. Im Allgemeinen empfehlen wir nicht, Felder auszublenden, da Code schwer lesbar ist.

2
sadjkas sadal

Variablen nehmen nicht an der Überarbeitung teil. Nur Methoden tun dies. Ein Methodenaufruf wird zur Laufzeit aufgelöst, dh, die Entscheidung zum Aufruf einer Methode wird zur Laufzeit getroffen, die Variablen werden jedoch nur zur Kompilierzeit festgelegt. Daher wird die Variable aufgerufen, deren Referenz für den Aufruf und nicht für das Laufzeitobjekt verwendet wird.

Schauen Sie sich den folgenden Ausschnitt an:

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);
  }

}

Wenn Sie den Code ausführen, zeigt die Konsole Folgendes an: 

Inside Honda
Inside Honda
Inside bike

Max_Speed = 150
Max_Speed = 90
Max_Speed = 90
0
Ananta S E

Natürlich ist es empfehlenswert, private Attribute und Getter und Setter zu verwenden, aber ich habe Folgendes getestet, und es funktioniert ... Siehe den Kommentar im 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 ... habe ich einfach die Regeln der Vererbung neu definiert oder habe ich Oracle in eine schwierige Situation gebracht? .. Für mich ist die geschützte statische Zeichenfolge eindeutig überschrieben, wie Sie sehen, wenn Sie dieses Programm ausführen. Es macht auch keinen Sinn, warum Attribute nicht überschreibbar sein sollten.

0
Pixel

Warum sollten Sie Variablen überschreiben, wenn Sie sie in den Unterklassen leicht neu zuordnen könnten?.

Ich folge diesem Muster, um das Sprachdesign umzugehen. Angenommen, Sie haben eine gewichtige Serviceklasse in Ihrem Framework, die in verschiedenen abgeleiteten Anwendungen in unterschiedlichen Ausprägungen verwendet werden muss. In diesem Fall können Sie die Superklassenlogik am besten konfigurieren, indem Sie ihre 'definierenden' Variablen neu zuweisen. 

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
premganz

Klassenvariablen (auch für Instanzvariablen anwendbar) weisen in Java kein überschreibendes Feature auf, da Klassenvariablen auf der Grundlage des Typs des aufrufenden Objekts aufgerufen werden. Es wurde eine weitere Klasse (Human) in der Hierarchie hinzugefügt, um sie klarer zu machen. So jetzt haben wir 

Sohn erweitert Vater verlängert Mensch

Im folgenden Code versuchen wir, über ein Array von Human-, Dad- und Son-Objekten zu iterieren, wobei jedoch in allen Fällen die Werte der Human-Klasse ausgegeben werden, da der Typ des aufrufenden Objekts Human war.

    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
        }
    }
}

Wird drucken

  • mensch
  • mensch
  • mensch

Also kein Überschreiben von Klassenvariablen.

Wenn wir auf die Klassenvariable des tatsächlichen Objekts von einer Referenzvariablen ihrer übergeordneten Klasse zugreifen möchten, müssen Sie dies dem Compiler explizit mitteilen, indem Sie den übergeordneten Verweis (Human-Objekt) in seinen Typ umwandeln.

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

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

Wird drucken

  • papa
  • sohn

Wie Teil dieser Frage: - Wie bereits vorgeschlagen, überschreiben Sie die printMe () -Methode in der Son-Klasse, dann beim Aufruf

Son().printMe();

Dads Klassenvariable "ich" wird ausgeblendet, da die nächste Deklaration (aus der Son-Klasse printme () -Methode) des "Ich" (in Son-Klasse) Vorrang hat.

0
Developer