Наследование в Java - PullRequest
       6

Наследование в Java

0 голосов
/ 19 октября 2010

Рассмотрим следующий код в Python:

class A(object):
    CLASS_ATTRIBUTE = 42

    def f(self):
        return "CLASS_ATTRIBUTE: %d" % self.CLASS_ATTRIBUTE

class B(A):
    CLASS_ATTRIBUTE = 44

Теперь A().f() и B().f() возвращают "CLASS_ATTRIBUTE: 42" и "CLASS_ATTRIBUTE: 44" соответственно.

Как мне добиться подобного эффекта в Java? Я хочу, чтобы поле CLASS_ATTRIBUTE было инициализировано статически и переопределено в унаследованном классе, но метод f должен быть определен только в базовом классе.

Ответы [ 5 ]

3 голосов
/ 19 октября 2010

Есть ли конкретная причина, по которой вы хотите, чтобы атрибут был статическим? В Java типичный способ сделать это состоит в том, чтобы A содержал защищенную переменную, которую вы затем устанавливали в конструкторах 2 классов:

public class A 
{
   protected int CLASS_ATTRIBUTE;
   public A()
   {
      CLASS_ATTRIBUTE = 42;
   } 

   public String f()
   {
      return "CLASS_ATTRIBUTE: " + CLASS_ATTRIBUTE;
   }

}

public class B extends A
{
   public B()
   {
      CLASS_ATTRIBUTE = 44;
   }
}

В качестве альтернативы (и, возможно, более совместимой с шаблонами проектирования Java) вы бы объявили функцию, которую вы можете переопределить для возврата значения вместо использования переменной-члена.

3 голосов
/ 19 октября 2010

Краткий ответ: вы не можете решить это так на Java.Вам придется решить ее по-другому.

В Java вы не можете переопределять или «переопределять» поля в подклассах, и вы не можете переопределять статические методы.

Это может бытьрешен с помощью уродливого рефлекса (хотя его следует избегать):

public class Main {
    public static void main(String... args) {

        A a = new A();
        B b = new B();

        System.out.println(a.f());             // Prints 42.
        System.out.println(a.fReflection());   // Prints 42.
        System.out.println(b.f());             // Prints 42.
        System.out.println(b.fReflection());   // Prints 44.
    }
}

class A {
    static int CLASS_ATTRIBUTE = 42;

    public int f() {
        return CLASS_ATTRIBUTE;
    }

    public int fReflection() {
        try {
            return getClass().getDeclaredField("CLASS_ATTRIBUTE").getInt(null);
        } catch (Exception wontHappen) {
            return -1;
        }
    }
}

class B extends A {
    // Compiles, but will not "override" A.CLASS_ATTRIBUTE.
    static int CLASS_ATTRIBUTE = 44;
}
1 голос
/ 19 октября 2010

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

Вам необходимо использовать защищенный метод "getter", который можетзатем переопределите его подклассом:

class A
{
private int attribute=42;

...

protected int getAttribute() {
    return attribute;
    }
}

class B
extends A
{
private int attribute=44;

...

protected int getAttribute() {
    return attribute;
    }
}

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

0 голосов
/ 19 октября 2010

При таком способе внедрения происходит как можно меньше вторжения. setAttribute() можно назвать чем-то вроде setDefaultValue(), если это понятнее.

public class A
{
    protected int attribute;

    public A()
    {
        setAttribute();
    }

    public String f()
    {
        return "CLASS_ATTRIBUTE: " + attribute;
    }

    protected void setAttribute()
    {
        attribute = 42;
    }
}


public class B extends A
{
    @Override
    protected void setAttribute()
    {
        attribute = 44;
    }
}


public class Main
{
    public static void main(String[] args)
    {
        A a = new A();
        B b = new B();
        System.out.println("A: " + a.f());
        System.out.println("B: " + b.f());
    }
}
0 голосов
/ 19 октября 2010

Я не уверен, что вы имели в виду буквально «статически» или нет, но вот краткий пример того, как наследование в его самой основной форме выглядит в Java.Обратите внимание, что использование метода get для доступа к переменной является лучшей идеей по нескольким причинам - это всего лишь пример.

public class Dog {
  protected String whatISay = "Woof!";
  public void speak(){
    System.out.println(whatISay);
  }
}


public class Poodle extends Dog {
  public Poodle(){
    whatISay = "Yap!";
  }
}


public class Main {
  public static void main(String[] args){
    Poodle fluffy = new Poodle();
    fluffy.speak();
    Dog dog = new Dog();
    dog.speak();
  }
}


Yap!
Woof!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...