Может ли ключевое слово this использоваться в абстрактном классе в Java? - PullRequest
21 голосов
/ 09 июня 2010

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

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

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

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

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

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

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

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

Ответы [ 3 ]

26 голосов
/ 09 июня 2010

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

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

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

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

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

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

Создание объектов абстрактных классов

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

Это является фактически созданным.

Ключевое слово abstract гарантирует, что при его создании оно создается в форме подкласса. Когда вы создаете экземпляр Dog, вы одновременно создаете экземпляр Animal! Таким образом, ссылка 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(). Вы бы увидели, что он печатает правда.

11 голосов
/ 09 июня 2010

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

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

1 голос
/ 13 сентября 2012

Код, который вы указали, содержит переменную 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 на защищенный, чтобы к нему можно было обращаться и из производного класса.

...