Вопрос по java – Переопределение переменных-членов в Java

51

Я изучаю переопределяющие функции-члены в JAVA и думал об экспериментах с переопределяющими переменными-членами.

Итак, я определил классы

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

Выход:

1
I am class A
1
I am class B

Я не могу понять, почему, когда aRef установлен в b, intVal все еще имеет класс A?

@Vic Seedoubleyew Но мне кажется, что это дубликатthis question Stelios Adamantidis
Возможный дубликатHiding instance variables of a class RBz
возможный дубликатSlight confusion regarding overriding where variables are concerned rob mayoff
Я думаю, что это не тот же вопрос, так как другой смешивает несколько особенностей языка, в то время как этот чисто о переменных, не являющихся полиморфными Vic Seedoubleyew

Ваш Ответ

10   ответов
10

There is no polymorphism for fields in Java.

Variables решение происходит во время компиляции, поэтому всегдаBase Class variables (не наследуемые переменные ребенка).

Поэтому всякий раз, когда происходит апскейтинг, всегда помните

1) Переменные базового класса будут доступны.

2) Будут вызваны методы подкласса (переопределенные методы, если переопределение произошло, иначе унаследованные методы, как и от родителя).

4

Концепция OverRiding в Java Функции будут переопределены в зависимости от типа объекта, а переменные будут доступны по ссылочному типу.

  1. Override Function: In this case suppose a parent and child class both have same name of function with own definition. But which function will execute it depends on object type not on reference type on run time.

Например:

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

Вотparent является ссылкой на родительский класс, но содержит объект дочернего класса, поэтому в этом случае будет вызываться функция дочернего класса.

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

Вотchild содержит объект дочернего класса, поэтому будет вызвана функция дочернего класса.

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

Вотparent содержит объект родительского класса, поэтому будет вызвана функция родительского класса.

  1. Override Variable: Java supports overloaded variables. But actually these are two different variables with same name, one in the parent class and one in the child class. And both variables can be either of the same datatype or different.

Когда вы пытаетесь получить доступ к переменной, это зависит от объекта ссылочного типа, а не от типа объекта.

Например:

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


The reference type is Parent so the Parent class variable is accessed, not the Child class variable.

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

Here the reference type is Child, so the Child class variable is accessed not the Parent class variable.

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

Here the reference type is Parent, so Parent class variable is accessed.

Добро пожаловать в ТАК. Пожалуйста, не форматируйте весь ответ как код. Выделите код как код и текст как текст. Спасибо
11

Переменные разрешаются во время компиляции, во время выполнения методов. ARef имеет тип A, поэтому aRef.Intvalue во время компиляции разрешается в 1.

67

Когда вы создаете переменную с тем же именем в подклассе, это называетсяhiding, Получившийся подкласс теперь будет фактически иметьboth свойства. Вы можете получить доступ к одному из суперкласса сsuper.var или же((SuperClass)this).var, Переменные даже не должны быть одного типа; это всего лишь две переменные с общим именем, очень похожие на два перегруженных метода.

@RahulRastogi Нет, это не имеет ничего общего с этой концепцией. & quot; Сокрытие данных & quot; это инкапсуляция.
Таким образом, делать такие вещи не полиморфизм в любом случае. Показывает ли это, что «скрытие данных» концепция ООП?
3

From JLS Java SE 7 Edition §15.11.1:

This lack of dynamic lookup for field accesses allows programs to be run efficiently with straightforward implementations. The power of late binding and overriding is available, but only when instance methods are used.

Ответы Оливера Чарльзворта и Марко Топольника верны, я хотел бы подробнее остановиться наwhy часть вопроса:

На явеученики являютсяaccessed в соответствии с типом ссылки, а не тип фактического объекта. По той же причине, если у вас былsomeOtherMethodInB() в классеBвы не сможете получить к нему доступ изaRef послеaRef = b это запустить. Идентификаторы (т. Е. Имена классов, переменных и т. Д.) Разрешаются во время компиляции, и поэтому для этого компилятор использует ссылочный тип.

Теперь в вашем примере, когда работаетSystem.out.println(aRef.intVal); он печатает значениеintVal определяется вA потому что это тип ссылки, которую вы используете для доступа к ней. Компилятор видит, чтоaRef имеет типA и этоintVal это будет доступ. Не забывайте, что у вас естьboth поля в случаяхB, У JLS также есть пример, аналогичный вашему, & quot; 15.11.1-1. Статическое связывание для доступа к полю & quot; если хочешь посмотреть.

Но почему методы ведут себя иначе? Ответ в том, что для методов Java используетlate binding, Это означает, что во время компиляции он находит наиболее подходящий метод дляsearch во время выполнения. Поиск включает случай переопределения метода в некотором классе.

0

Ну, я надеюсь, у тебя есть ответ. Если нет, вы можете попробовать посмотреть в режиме отладки. подкласс B имеет доступ как к intVal. Они не полиморфны, следовательно, они не переопределены.

Если вы воспользуетесь ссылкой B, вы получите IntVal B. Если вы используете ссылку A, вы получите IntVal A. Это так просто.

Спасибо за ответ Kalyan Raghu
Я думаю, что было недоразумение. До того момента, когда вы не присвоили b aRef, у него был только один intVal. Когда вы присвоили b aRef, теперь он указывает на объект типа B, следовательно, два intVals.
В режиме отладки я вижу, что и b, и aRef имеют оба значения intVal, тогда как согласно вашему комментарию я ожидал, что только объект b будет иметь оба значения. Это потому, что отладчик ведет себя не так, как JVM? Kalyan Raghu
51

Переменные не являются полиморфными в Java; они не перекрывают друг друга.

Таким образом, поскольку переменная не переопределяется, для них не выполняется разрешение во время выполнения, поэтому в цепочке наследования при обращении используется тип переменной ссылочного класса вместо типа объекта. Я проверил это с помощью расширения классов и использования промежуточного ссылочного типа. Спасибо за ответ. Kalyan Raghu
0

Согласно спецификациям Java, переменные экземпляра не переопределяются из суперкласса подклассом, когда он расширяется.

Следовательно, переменная только в подклассе может рассматриваться как переменная с одинаковым именем.

Также, когда конструктор A вызывается во время создания экземпляра B, переменная (intVal) инициализируется и, следовательно, выводится.

Я не получил первое очко. Мы всегда можем получить доступ к любым не закрытым переменным-членам суперкласса в подклассе. Kalyan Raghu
1

Я надеюсь, что это может помочь:

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

Таким образом, переопределение переменной базового класса невозможно, но значение переменной базового класса можно установить (изменить) из конструктора наследуемого класса.

Добро пожаловать в переполнение стека! Как правило, ответы гораздо полезнее, если они включают в себя объяснение того, для чего предназначен код, и почему это решает проблему, не представляя других.
-2

У Java есть перо инкапсуляции, что означает, что он тесно связывает свойство и поведение объекта. так что только через ссылку на класс мы можем вызвать его поведение, чтобы изменить его свойство.

и в методе наследования только метод переопределяет, так что он может влиять только на его свойство.

Похожие вопросы