Есть ли способ получить доступ к элементу подкласса из суперкласса? - PullRequest
0 голосов
/ 12 июля 2019

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

Я пытался использовать метод получения для свойства, но получил тот же результат.

public class SuperClass {
    private static final String a = "Super";

    public void superMethod(){
        System.out.println("SuperMethod: " + a);
    }

}

public class ChildClass extends SuperClass {

    private static final String a = "Child";

}

public class Main {
    public static void main(String[] args) {
        SuperClass s = new SuperClass();
        ChildClass c = new ChildClass();
        s.superMethod();
        c.superMethod();
    }
}

Консоль показывает:

СуперМетод: Супер

СуперМетод: Супер

Ожидаемый результат:

СуперМетод: Супер

СуперМетод:Ребенок

Ответы [ 3 ]

5 голосов
/ 12 июля 2019

Я пытался использовать геттер для свойства, но получил тот же результат.

Вы уверены?Следующее должно быть именно тем, что вы ищете:

class SuperClass {

    private String a = "Super";

    public void superMethod() {
        System.out.println("SuperMethod: " + getA());
    }

    public String getA() {
        return this.a;
    }

}

class ChildClass extends SuperClass {

    private String a = "Child";

    @Override
    public String getA() {
        return this.a;
    }

}

public class Main {

    public static void main(String[] args) {
        SuperClass s = new SuperClass();
        ChildClass c = new ChildClass();
        s.superMethod();
        c.superMethod();
    }
}

Обратите внимание, что геттеры не могут быть частными (иначе они не могут быть доступны извне класса), и они не могут быть статическими(иначе они являются частью класса, а не экземплярами этого класса.)

1 голос
/ 12 июля 2019

Не совсем точно, что вы делаете, но ваши String a члены private static члены класса, а не отдельных объектов.

Если вы сделали String a членом объекта, а не класса, вы можете переопределить значение при создании дочернего класса:

U:\>jshell
|  Welcome to JShell -- Version 12
|  For an introduction type: /help intro

jshell> class SuperClass {
   ...>    protected final String a;
   ...>
   ...>    protected SuperClass(String _a) {
   ...>       a = _a;
   ...>    }
   ...>
   ...>    public SuperClass() {
   ...>       this("Super");
   ...>    }
   ...>
   ...>    public void superMethod() {
   ...>       System.out.println("SuperMethod: "+a);
   ...>    }
   ...> }
|  created class SuperClass

jshell> class ChildClass extends SuperClass {
   ...>    public ChildClass() {
   ...>      super("Child");
   ...>    }
   ...> }
|  created class ChildClass

jshell> var s = new SuperClass();
s ==> SuperClass@4566e5bd

jshell> var c = new ChildClass();
c ==> ChildClass@ff5b51f

jshell> s.superMethod();
SuperMethod: Super

jshell> c.superMethod();
SuperMethod: Child

Обновление

Теперь, когда мы знаем ваш реальный вариант использования (из комментария ниже), то, что вы хотите реализовать, довольно просто:

class SuperClass {
    private final static Logger LOG = Logger.getLogger(SuperClass.class);

    protected Logger getLogger() { return LOG; }

    public void superMethod(){
        getLogger().info("superMethod() called.");
    }
}

class ChildClass extends SuperClass {
    private final static Logger LOG = Logger.getLogger(ChildClass.class);

    @Override
    protected Logger getLogger() { return LOG; }
}

public class Main {
    public static void main(String[] args) {
        SuperClass s = new SuperClass();
        ChildClass c = new ChildClass();
        s.superMethod();                 // Message logged to SuperClass.LOG
        c.superMethod();                 // Message logged to ChildClass.LOG
    }
}
0 голосов
/ 12 июля 2019

Краткий ответ: Java не может сделать это так, как вы хотите, так как компилятор объединит строковый литерал с конечными значениями, поэтому "SuperMethod: " + a будет преобразован в "SuperMethod: Super" в полученном байт-коде.

Единственное решениеиспользует отражение (если необходимо):

import java.lang.reflect.Field;

public class Main {
  public static void main(String[] args) {
      SuperClass s = new SuperClass();
      ChildClass c = new ChildClass();
      s.superMethod();
      c.superMethod();
  }
}

class SuperClass {
    private static final String a = "Super";

    public void superMethod(){
      try{
        final Class<?> clazz = this.getClass();
        final Field fieldA = clazz.getDeclaredField("a");
        fieldA.setAccessible(true);

        final String value = (String)fieldA.get(null);

        System.out.println("SuperMethod: " + value);
      } catch (final NoSuchFieldException | IllegalAccessException ex){
        // Because reflection
        ex.printStackTrace();
      }
    }
}

class ChildClass extends SuperClass {
    private static final String a = "Child";
}

Вывод:

SuperMethod: Super
SuperMethod: Child

Но, честно говоря, я все же предпочел бы использовать классическое переопределение:

public class Main {
  public static void main(String[] args) {
      SuperClass s = new SuperClass();
      ChildClass c = new ChildClass();
      s.superMethod();
      c.superMethod();
  }
}

class SuperClass {
    private static final String a = "Super";

    public void superMethod(){
        System.out.println("SuperMethod: " + getA());
    }

    public String getA() {
      return a;
    }

}

class ChildClass extends SuperClass {

    private static final String a = "Child";

    @Override
    public String getA() {
      return a;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...