webentwicklung-frage-antwort-db.com.de

Member-Variablen in Java überschreiben

Ich studiere das Überschreiben von Memberfunktionen in Java und überlege, ob ich mit Membervariablen überschreiben möchte.

Also habe ich Klassen definiert

public class A{
    public int intVal = 1;
    public void identifyClass()
    {
        System.out.println("I am class A");
    }
}

public class B extends A
{
    public int intVal = 2;
    public void identifyClass()
    {
        System.out.println("I am class B");
    }
}

public class mainClass
{
    public static void main(String [] args)
    {
        A a = new A();
        B b = new B();
        A aRef;
        aRef = a;
        System.out.println(aRef.intVal);
        aRef.identifyClass();
        aRef = b;
        System.out.println(aRef.intVal);
        aRef.identifyClass();
    }
}

Die Ausgabe ist:

1
I am class A
1
I am class B

Ich kann nicht verstehen, warum, wenn aRef auf b gesetzt ist, intVal noch Klasse A ist?

51
Kalyan Raghu

Wenn Sie eine Variable mit demselben Namen in einer Unterklasse erstellen, wird dies als hiding bezeichnet. Die resultierende Unterklasse enthält nun tatsächlich beide Eigenschaften. Sie können von der Superklasse aus mit super.var oder ((SuperClass)this).var darauf zugreifen. Die Variablen müssen nicht einmal vom selben Typ sein. Dies sind nur zwei Variablen, die einen Namen teilen, ähnlich wie zwei überladene Methoden.

67
Marko Topolnik

Variablen sind in Java nicht polymorph; Sie überschreiben sich nicht.

51

Variablen werden zur Laufzeit während der Kompilierung aufgelöst. Der aRef ist vom Typ A, daher wird aRef.Intvalue zu 1 kompiliert.

11
Rostislav Matl

Es gibt keinen Polymorphismus für Felder in Java.  

Die Entscheidung Variables geschieht zur Kompilierzeit, daher wird immer auf Base Class-Variablen (nicht auf untergeordnete Variablen von Kindern) zugegriffen.

Also, wann immer Upcasting passiert, immer daran denken

1) Auf Variablen der Basisklasse wird zugegriffen.

2) Sub-Klassen-Methoden (überschriebene Methoden, wenn das Überschreiben mit anderen geerbten Methoden vom übergeordneten Objekt passiert) werden aufgerufen.

10
Ankur Singhal

OverRiding Concept in Java Funktionen werden je nach Objekttyp überschrieben und auf Variablen wird auf Referenztyp zugegriffen. 

  1. Funktion überschreiben: In diesem Fall wird angenommen, dass eine übergeordnete und eine untergeordnete Klasse denselben Funktionsnamen mit eigener Definition haben. Welche Funktion ausgeführt wird, hängt jedoch vom Objekttyp ab, nicht vom Referenztyp zur Laufzeit.

Für z.B.

Parent parent=new Child();
parent.behaviour();

Hier ist parent eine Referenz der Parent-Klasse, enthält jedoch ein Objekt der Child-Klasse, daher wird in diesem Fall die Child-Klassenfunktion aufgerufen.

Child child=new Child();
child.behaviour();

Hier enthält child ein Objekt der Child-Klasse, daher wird die Child-Klassenfunktion aufgerufen.

Parent parent=new Parent();
parent.behaviour();

Hier enthält parent das Objekt der übergeordneten Klasse, daher wird die Funktion der übergeordneten Klasse aufgerufen.

  1. Variable überschreiben: Java unterstützt überladene Variablen. Tatsächlich sind dies jedoch zwei verschiedene Variablen mit demselben Namen, eine in der übergeordneten Klasse und eine in der untergeordneten Klasse. Und beide Variablen können entweder den gleichen Datentyp haben oder sich unterscheiden.

Wenn Sie versuchen, auf die Variable zuzugreifen, hängt sie vom Objekt des Referenztyps ab, nicht vom Objekttyp.

Für z.B.

Parent parent=new Child();
System.out.println(parent.state);

Der Referenztyp ist Parent, sodass auf die Parent-Klassenvariable zugegriffen wird, nicht auf die Child-Klassenvariable.

Child child=new Child();
System.out.println(child.state);

Der Referenztyp ist hier Child, daher wird nicht auf die Child-Klassenvariable, sondern auf die Parent-Klassenvariable zugegriffen.

Parent parent=new Parent();
System.out.println(parent.state);

Hier ist der Referenztyp Parent, also wird auf Parent-Klassenvariable zugegriffen.

4
Aman Goyal

Ab JLS Java SE 7 Edition §15.11.1:

Dieses Fehlen einer dynamischen Suche nach Feldzugriffen ermöglicht die effiziente Ausführung von Programmen mit einfachen Implementierungen. Die Möglichkeit des späten Bindens und Überschreibens ist nur verfügbar, wenn Instanzmethoden verwendet werden.

Die Antworten von Oliver Charlesworth und Marko Topolnik sind korrekt. Ich möchte etwas näher auf den warum-Teil der Frage eingehen:

In Java Klassenmitgliedern sind auf die zugegriffen wird entsprechend dem Typ der Referenz und nicht dem Typ des eigentlichen Objekts. Aus demselben Grund könnten Sie, wenn Sie eine someOtherMethodInB() in der Klasse B hätten, nicht auf aRef zugreifen, nachdem aRef = b ausgeführt wurde. Bezeichner (z. B. Klassen-, Variablennamen usw.) werden zur Kompilierzeit aufgelöst, und der Compiler verwendet hierfür den Referenztyp.

Wenn Sie in diesem Beispiel System.out.println(aRef.intVal); ausführen, wird der in intVal definierte Wert von A ausgegeben, da dies der Typ der Referenz ist, die Sie für den Zugriff darauf verwenden. Der Compiler sieht, dass aRef vom Typ A ist, und dies ist die intVal, auf die er zugreifen wird. Vergessen Sie nicht, dass Sie beide Felder in den Instanzen von B haben. JLS hat auch ein ähnliches Beispiel wie "15.11.1-1. Statische Bindung für den Feldzugriff", wenn Sie einen Blick darauf werfen möchten.

Aber warum verhalten sich Methoden anders? Die Antwort ist, dass Java für Methoden late binding verwendet. Das bedeutet, dass es zur Kompilierzeit die geeignetste Methode für search für die Laufzeit findet. Die Suche umfasst den Fall, dass die Methode in einer Klasse überschrieben wird.

3

Dies wird als Variablenverstecken bezeichnet . Wenn Sie aRef = b; zuweisen, hat aRef zwei intVal, 1 heißt nur intVal, und eine andere ist unter A.intVal verborgen (siehe Debugger-Screenshot). Da Ihre Variable vom Typ class A ist, greift Java auch dann auf A.intVal zu, wenn Sie nur intVal drucken.

Antwort 1 : Eine Möglichkeit, auf die intVal einer untergeordneten Klasse zuzugreifen, ist System.out.println((B)aRef.intVal);

Antwort 2 : Eine andere Möglichkeit ist Java Reflection, da Java, wenn Sie Reflection verwenden, versteckten A.intVal basierend auf dem Klassentyp nicht intelligent erfassen kann, den Variablennamen als Zeichenfolge übernehmen muss -

import Java.lang.reflect.Field;

class A{
    public int intVal = 1;
    public void identifyClass()
    {
        System.out.println("I am class A");
    }
}

class B extends A
{
    public int intVal = 2;
    public void identifyClass()
    {
        System.out.println("I am class B");
    }
}

public class Main
{
    public static void main(String [] args) throws Exception
    {
        A a = new A();
        B b = new B();
        A aRef;
        aRef = a;
        System.out.println(aRef.intVal);
        aRef.identifyClass();
        aRef = b;
        Field xField = aRef.getClass().getField("intVal");
        System.out.println(xField.get(aRef));
        aRef.identifyClass();
    }
}

Ausgabe -

1
I am class A
2
I am class B

 enter image description here 

1
sapy

Ich hoffe das kann helfen

public class B extends A {
//  public int intVal = 2;

    public B() {
        super();
        super.intVal = 2;
    }

    public void identifyClass() {
        System.out.println("I am class B");
    }
}
0

Gemäß den Java-Spezifikationen werden die Instanzvariablen bei der Erweiterung nicht von einer Unterklasse durch eine Unterklasse überschrieben.

Daher kann nur die Variable in der Unterklasse als eine mit demselben Namen bezeichnet werden.

Auch wenn der Konstruktor von A während der Instanzerstellung von B aufgerufen wird, wird die Variable (intVal) initialisiert und damit die Ausgabe.

0
Siddharth Singh

Ich hoffe, du hast die Antwort bekommen. Wenn nicht, können Sie versuchen, den Debug-Modus anzuzeigen. Die Unterklasse B hat Zugriff auf beide Werte. Sie sind nicht polymorph und werden daher nicht überschrieben.

Wenn Sie die Referenz von B verwenden, erhalten Sie das IntVal von B. Wenn Sie die Referenz von A verwenden, erhalten Sie das IntVal von A. So einfach ist das.

0
dharam