Обратитесь к «этому» подклассу вместо «этого» суперкласса в Java? - PullRequest
0 голосов
/ 02 апреля 2020

Я создал суперкласс и пакет подклассов для одного из моих текущих Java проектов - в этом случае я хочу определить функцию в суперклассе, которая будет наследоваться всеми подклассами. Эта функция будет использовать «this» для ссылки на атрибуты в подклассах, но вместо этого это относится к атрибутам в SUPERclasses.

Fe, я создал суперкласс и подкласс, где оба класса имеют атрибут «значение». Функция используется для распечатки значения, где «this» должно относиться к текущему классу.

public class Main{
    public static void main(String[] args) {
        Child myObject = new Child();
        myObject.printValue();
    }
}

class Parent{
    private int value = 10;
    public void printValue(){
        System.out.println(this.value);
    }
}

class Child extends Parent{
    private int value = 20;
}

В этом случае я хочу указать значение в подклассе (20), используя «это» для ссылки на текущий класс. Но «this» в настоящее время относится к «значению» в SUPERclass, в результате чего печатается одно и то же сообщение для всех подклассов.

Можно ли установить «this» для ссылки на класс, в котором используется функция?

Ответы [ 5 ]

1 голос
/ 02 апреля 2020

Это не работает, потому что поля не могут быть переопределены в подклассах. Только методы могут быть переопределены.

Вы можете получить нужный эффект, если создадите метод getValue, заменив this.value вызовом getValue.

class Parent{
    private int value = 10;
    public void printValue(){
        System.out.println(getValue());
    }
    protected int getValue() {
        return value;
    }
}

class Child extends Parent{
    private int value = 20;

    @Override
    protected int getValue() {
        return value;
    }
}
0 голосов
/ 02 апреля 2020

Одна возможность, которую вы можете развлечь, - это использовать отражение для доступа к полям текущего класса. Метод getClass возвращает фактический класс объекта, поэтому для объекта класса Child он возвращает класс Child, даже если код находится в классе Parent. Вы можете получить доступ к полям, объявленным этим классом, используя метод getDeclaredField().

class Parent{
    private int value = 10;

    private int getValueWithReflection() {
        try {
            Field valueField = getClass().getDeclaredField("value");
            valueField.setAccessible(true);
            return valueField.getInt(this);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public void printValue(){
        System.out.println(getValueWithReflection());
    }
}

class Child extends Parent{
    private int value = 20;
}
0 голосов
/ 02 апреля 2020

Основной ответ c заключается в том, что при использовании простого доступа к переменной невозможно обеспечить динамическое разрешение переменной относительно конкретного типа экземпляра, к которому осуществляется доступ. Какая переменная будет разрешена, зависит от объявленного типа экземпляра, к которому осуществляется доступ. Например:

public class SampleGrandparent {
    public static void main(String[] args) {
        (new SampleChild(0)).printMe();
    }

    public int value;

    public SampleGrandparent(int value) {
        this.value = value;
    }

    public static class SampleParent extends SampleGrandparent {
        @SuppressWarnings("hiding")
        public int value;

        public SampleParent(int value) {
            super(value + 1);

            this.value = value;
        }

    }

    public static class SampleChild extends SampleParent {
        @SuppressWarnings("hiding")
        public int value;

        public SampleChild(int value) {
            super(value + 1);

            this.value = value;
        }

        public void printMe() {
            System.out.println("Child Value [ " + value + " ]");
            System.out.println("Parent Value [ " + ((SampleParent) this).value + " ]");
            System.out.println("Grandparent Value [ " + ((SampleGrandparent) this).value + " ]");
        }
    }
}

Для динамического разрешения c необходимо будет использовать методы.

Частично это можно обойти, но только если известны все переменные и имена подклассов. суперклассу. Например:

public class SampleGrandparent {
    public static void main(String[] args) {
        SampleGrandparent gp = new SampleParent(0);
        gp.printMe();
    }

    public int value;

    public SampleGrandparent(int value) {
        this.value = value;
    }

    public void printMe() {
        if ( this instanceof SampleChild ) {
            System.out.println("Child Value [ " + ((SampleChild) this).value + " ]");
        }
        if ( this instanceof SampleParent) {
            System.out.println("Parent Value [ " + ((SampleParent) this).value + " ]");
        }
        System.out.println("Grandparent Value [ " + value + " ]");
    }

    public static class SampleParent extends SampleGrandparent {
        @SuppressWarnings("hiding")
        public int value;

        public SampleParent(int value) {
            super(value + 1);

            this.value = value;
        }

    }

    public static class SampleChild extends SampleParent {
        @SuppressWarnings("hiding")
        public int value;

        public SampleChild(int value) {
            super(value + 1);

            this.value = value;
        }
    }
}

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

Все это становится довольно уродливым и не рекомендуется.

0 голосов
/ 02 апреля 2020

Мы будем использовать ключевое слово this для доступа к текущему классу и используем ключевое слово super для доступа к суперклассу. Мы не можем получить доступ к подклассам в суперклассе, потому что у него нет привилегий. Идея наследования в Java состоит в том, что вы можете создавать новые классы, которые основаны на существующих классах и имеют свои уникальные свойства, которые отличаются от их родителей. Если вы хотите получить доступ к свойствам суперкласса, вам нужно написать метод в подклассах для доступа. Если вы все еще хотите получить доступ к свойствам подкласса в суперклассе, почему вы заставляете подклассы расширять суперкласс.

public class Main{
     public static void main(String[] args) {
            Child myObject = new Child();
            myObject.printValue();
            myObject.printSuperValue();
        }
}

    class Parent{
        private int value = 10;
        public void printValue(){
            System.out.println(this.value);
        }
    }

    class Child extends Parent{
        private int value = 20;


        @Override
        public void printValue(){
            System.out.println(this.value);
        }

        public void printSuperValue(){
            super.printValue();
        }
    }

Надеюсь, это поможет вам.

0 голосов
/ 02 апреля 2020

Ключевым моментом здесь является то, что «не пытайтесь переопределить поля суперкласса», потому что java не поддерживает это. Если у вас есть поле «значение» в подклассе, то отбросьте его и вместо этого используйте поле из суперкласса. Создайте метод установки в суперклассе, чтобы установить значение или использовать конструктор. Будет работать следующий код:

public class Main {
    public static void main(String[] args) {
        Child myObject = new Child();
        myObject.setValue(20);      // whatever value you want 
        myObject.printValue();
    }
}

class Parent{
    private Integer value = 10;
    public void setValue(Integer value) {
        this.value = value;
    }

    public void printValue(){
        System.out.println(value);
    }
}

class Child extends Parent{

}

Если вам абсолютно необходимо иметь отдельное поле «значение» в подклассе, честно говоря, я думаю, что дизайн класса неправильный. Вы должны назвать поле по-другому (например, «value2»), потому что java будет обрабатывать его как поле, отличное от поля с тем же именем в суперклассе. Создайте свой код так, чтобы иметь свойство childObject.setValue (value2) где-то перед вызовом printValue ()

...