0

Java: статическое поле в абстрактном классе

9

Проблема:

Я только начал работать с Java и столкнулся с проблемой, связанной с статическими переменными в абстрактных классах. У меня есть следующий пример, который лучше всего иллюстрирует суть моей проблемы:

public abstract class A {
    static String str;
}

public class B extends A {
    public B() {
        str = "123";
    }
}

public class C extends A {
    public C() {
        str = "abc";
    }
}

public class Main {
    public static void main(String[] args) {
        A b = new B();
        A c = new C();
        System.out.println("b.str = " + b.str);
        System.out.println("c.str = " + c.str);
    }
}

Этот код выводит следующие результаты:

b.str = abc
c.str = abc

Как видно, переменная str является статической и разделяется между всеми экземплярами классов B и C, поэтому и b.str, и c.str выводят одно и то же значение "abc".

Желаемое решение:

Я хотел бы, чтобы каждая подкласс, создающий экземпляр суперкласса, имел собственную переменную класса. При этом я хочу иметь возможность ссылаться на эту переменную через идентификатор или метод, определенный в абстрактном суперклассе.

В идеале, я хотел бы получить следующий вывод:

b.str = 123
c.str = abc

Можно ли это реализовать?

5 ответ(ов)

0

Если вы хотите, чтобы классы B и C имели отдельные статические переменные, вам нужно объявить эти переменные в соответствующих классах. В общем, статические члены и полиморфизм плохо сочетаются.

Обратите внимание, что доступ к статическим членам через ссылки - это очень плохая идея с точки зрения читаемости кода. Это создает впечатление, что поведение зависит от значения ссылки, хотя это не так. Поэтому ваш текущий код даже не скомпилируется, если вы переместите str в классы B и C. Вместо этого вам потребуется следующее:

System.out.println("b.str = " + B.str);
System.out.println("c.str = " + C.str);

Если вам действительно нужно иметь доступ к значению полиморфно (т.е. через экземпляр класса A), то одним из вариантов является создание полиморфного геттера:

public class A {
    public abstract String getStr();
}

public class B extends A {
    private static String str = "b";

    @Override public String getStr() {
        return str;
    }
}

(и аналогично для класса C).

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

0

Ваша реализация выглядит хорошо, и если вы хотите, чтобы класс A имел возможность устанавливать и получать значение переменной str, то добавление методов доступа (геттеров и сеттеров) — это правильный подход.

Вот пример кода с вашими дополнениями:

public abstract class A {
    private String str;
    public String getStr() { return str; }
    protected void setStr(String str) { this.str = str; }
}

// Пример использования
B b = new B();
b.getStr(); // Получаем значение str

В данном случае, чтобы B мог получить значение str, класс B должен наследоваться от класса A и может использовать метод getStr().

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

protected static Map<Class<?>, String> values = new HashMap<>();
public abstract String getValue();

И затем реализовать методы getValue и setValue следующим образом:

public String getValue() {
    return values.get(getClass());
}
public void setValue(String value) {
    values.put(getClass(), value);
}

Однако стоит отметить, что использование статических переменных для каждого подкласса может привести к потенциальным проблемам с потокобезопасностью и управлением данными, поэтому такой подход обычно не рекомендуется. Лучше использовать экземпляры класса для хранения состояния.

0

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

  1. Создайте абстрактный класс с абстрактным методом:
abstract class A {
    abstract String getStr();
}
  1. В каждом подклассе объявите статическую переменную и реализуйте метод getStr(), чтобы он возвращал значение этой статической переменной:
public class B extends A {
    private static String str = "Hello from B";

    @Override
    public String getStr() {
        return B.str;
    }
}

public class C extends A {
    private static String str = "Hello from C";

    @Override
    public String getStr() {
        return C.str;
    }
}

Таким образом, каждый подкласс имеет свою собственную статическую переменную str, и метод getStr() возвращает значение этой переменной. Вы можете добавлять столько подклассов, сколько вам нужно, и каждый из них будет иметь свою реализацию метода getStr(), возвращающую соответствующее значение.

0

Вопрос: Почему статическая переменная загружается в систему только один раз, и почему оба раза при выводе печатается "abc"?

Ответ: Статическая переменная в Java (или в других языках программирования) действительно загружается в систему в самом начале, до загрузки класса. Это объясняет, почему существует только один экземпляр этой переменной для всего класса, и все экземпляры классов имеют доступ к одной и той же статической переменной.

Что касается вывода "abc" в обоих случаях, причина заключается в том, что вы устанавливаете значение переменной str равным "abc" в последнем месте кода. Таким образом, когда вы обращаетесь к этой статической переменной, она уже была обновлена в процессе выполнения программы. Поэтому оба раза, когда вы выводите значение str, результат будет "abc".

Если у вас есть дополнительные вопросы о работе со статическими переменными, не стесняйтесь задавать!

0

Этот код выведет на экран нужный вам результат:

public abstract class A{
}

public class B extends A{
    static String str;

    public B(){
        str = "123";
    }
}

public class C extends A{
    static String str;

    public C(){
        str = "abc";
    }
}

public class Main{

    public static void main(String[] args){
        A a = new B();
        A c = new C();
        System.out.println("B.str = " + B.str);
        System.out.println("C.str = " + C.str);
    }
}

Когда вы выполните этот код, он создаст экземпляры классов B и C, которые инициализируют свои статические поля str. Результатом выполнения программы будет:

B.str = 123
C.str = abc

Статические поля str являются общей частью классов B и C, и их значения изменяются при создании новых объектов этих классов. Поэтому, при выводе значений B.str и C.str, вы получите соответственно "123" и "abc".

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь