Подтвердить что ты не робот

Может ли ключевое слово this использоваться в абстрактном классе в Java?

Я попробовал с приведенным ниже примером, он работает нормально.

Я ожидал, что он будет выбирать значение подкласса, поскольку объект не будет создан для суперкласса (как абстрактного). Но он выбирает только значение поля суперкласса.

Пожалуйста, помогите мне понять, что это за концепции?

abstract class SuperAbstract {
    private int a = 2;
    public void funA() {
        System.out.println("In SuperAbstract: this.a " + a);
    }
}

class SubClass extends SuperAbstract {
    private int a = 34;
}

Я звоню new SubClass.funA();

Я ожидаю, что он напечатает 34, но он печатает 2.

P.S.: Что я хочу знать, почему использование этого в абстрактном классе не дает мне ошибку?

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

Внутри метода экземпляра или конструктор, это ссылка на текущий объект - объект, чей метод или конструктор. Вы можете обратиться к любому члену текущий объект из экземпляра метод или конструктор, используя это. от: http://java.sun.com/docs/books/tutorial/java/javaOO/thiskey.html

4b9b3361

Ответ 1

Чтобы ответить на вопрос в заголовке: Да, this можно использовать в абстрактном классе. Абстрактное Animal создается одновременно с Dog.

Переопределяющие поля

Вы не можете переопределить поля так, как вы это пробовали. Поля "не являются виртуальными", как методы.

Краткий справочник по Java: перегрузка, переопределение, типы времени выполнения и ориентация объекта - переопределение методов

  • поля нельзя переопределить, но они могут быть скрыты, т.е. если вы объявляете поле в подклассе с тем же именем, что и в суперклассе, доступ к полю суперкласса возможен только с использованием типа super или superclass

Если бы вы могли, поле, вероятно, должно быть хотя бы защищено :-)


поскольку объект не будет создан для суперкласса (так как он абстрактный)

На самом деле это экземпляр.

Ключевое слово abstract только гарантирует, что при его создании оно было создано в форме подкласса. Когда вы создаете экземпляр Dog, вы одновременно создаете экземпляр Animal ! Таким this ссылка this в контексте Animal всегда будет относиться к Dog Cat или чему-то еще, но во всех случаях она относится к какому-то Animal. :-)

Как показано в примере ниже, ссылка this имеет смысл даже в абстрактном классе:

abstract class Animal {
    public String name;

    public Animal(String name) {
        System.out.println("Constructing an Animal");
        this.name = name;
    }

    public abstract void speak();
}

class Dog extends Animal {
    public Dog(String name) {
        super(name);
        System.out.println("  Constructing a Dog");
    }
    public void speak() {
        System.out.println("Bark! My name is " + name);
    }
}

public class Test {
    public static void main(String... args) {
        new Dog("Woffy").speak();
    }
}

Печать:

Constructing an Animal
  Constructing a Dog
Bark! My name is Woffy

Обновление: this ссылка ссылается на тот же объект в суперклассе, что и в подклассе.

Вы можете попробовать добавить

public Animal getSuperThis() { return this; }

в классе животных, и делать

System.out.println(this == getSuperThis());

в Dog.speak(). Вы бы увидели, что это печатает правда.

Ответ 2

Любое поле, объявленное в классе, уникально, даже если оно имеет то же имя, что и поле в базовом классе (т.е. только методы могут быть переопределены, но не поля). Поэтому в производном классе есть два разных поля: SuperAbstract.a и SubClass.a. Тот факт, что базовый класс abstract не влияет.

Ключевое слово abstract просто означает, что класс не может быть создан, т.е. вы не можете написать new SuperAbstract(). Вы можете только создать объект подкласса, который должен переопределить все методы, отмеченные abstract.

Ответ 3

Предоставленный вами код содержит переменную a как частный член класса SuperAbstract. Поскольку, похоже, вы не переопределяете функцию, она представляет код из класса SuperAbstract, и выполнение этого процесса получит доступ к a, объявленному в самом классе, независимо от того, что он вызывается из любой унаследованный класс. Чтобы получить доступ к значению более поздней переменной, вам необходимо переопределить функцию, снова определив функцию в производном классе. Окончательный код выглядит следующим образом:

abstract class SuperAbstract {
    protected int a = 2;
    public void funA() {
        System.out.println("In SuperAbstract:" + this.a);
    }
}

class SubClass extends SuperAbstract {
    private int a = 34;
    //Overriding the above function
    public void funA() {
        System.out.println("In SubClass: " + a);
        //Or even check using the super keyword
        System.out.println("In SubClass with super: " + super.a);
        //Now call the function to display the value of a from SuperAbstract
        super.funA();
    }
}

В приведенном выше коде я изменил a на защищенный, так что к нему также можно было получить доступ из производного класса.