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

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

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

Итак, я хотел бы, чтобы результат был:

b.str = 123

c.str = abc

Это выполнимо?

4b9b3361

Ответ 1

Если вы хотите, чтобы классы 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).

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

Ответ 2

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

Установщик и геттер - это мое дополнение, вы можете просто сделать переменную нестатической.

Обновить. Если вы хотите иметь статический для подкласса, вы можете:

protected static Map<Class, String> values;
public abstract String getValue();

а затем:

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

Но это, как правило, плохая идея.

Ответ 3

Поместите статическую varibale в каждый подкласс и добавьте абстрактный абстрактный метод (не статический) в абстрактный суперкласс:

abstract String getStr();

Затем реализуем метод getStr() в каждом подклассе, возвращая статическое поле этого специального подкласса.

public class B extends A {
 private static String str;

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

Ответ 4

в системе присутствует только один экземпляр статической переменной.

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

причина, по которой печатается время abc, заключается в том, что вы устанавливаете значение str как abc в последнем.

Ответ 5

Это напечатает желаемый результат:

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

Ответ 6

Так как вы в любом случае жестко кодируете значение или str в подклассах, вы можете сделать что-то вроде этого:

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

public class B extends A{
   public String getStr(){
      return "123";
   }
}

public class C extends A{
   public String getStr(){
      return "abc";
   }
}

Это сделало бы трюк в вашем случае.

Конечно, тогда вы должны вызвать его методом, например:

public class Main{

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

Ответ 7

Это то, что я сделал, чтобы избежать реализации одного и того же метода во всех подклассах. Он основан на ответе Божо. Может быть, это может помочь кому-то.

import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author Uglylab
 */
public class SandBox {

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

}
 abstract class A{
    protected static Map<Class, String> values = new HashMap<>();


    public static String getStr(Class<? extends A> aClass) {
        return values.get(aClass);
    }

    public static void setStr(Class<? extends A> aClass, String s) {
        values.put(aClass, s);
    }

}

 class B extends A{
    public B(){
        setStr(this.getClass(),"123");
    }
}

 class C extends A{
    public C(){
        setStr(this.getClass(),"abc");
    }
}

Ответ 8

Я думаю, что один из способов приблизиться к этому - использовать singleton для классов B и C для имитации статических методов и полей. Они могут расширять абстрактный класс A, но будут иметь свои собственные значения str..