2010-10-19 3 views
0

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

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 должен быть определен только в базовом классе.

ответ

0

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

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!

+0

@ user480884, Ничего себе, вы не должны были статически ставить в своем вопросе. – aioobe

+0

Это самое близкое к моим ожиданиям. Если бы я мог избавиться от этого конструктора в подклассе ... По крайней мере для базового класса это поле инициализируется статически (по крайней мере, это выглядит так - я не знаком с Java, если честно). – user480884

+0

А, я вижу ... – aioobe

3

Короткий ответ: вы не можете решить его, как это на 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; 
} 
+0

Ну, я не требую, чтобы соответствующее поле было статическим в Java. Я просто хочу иметь аналогичную функциональность без написания страниц кода. – user480884

+0

Тем не менее, вы не можете инициализировать переменную статически, а затем статически «повторно инициализировать» экземпляр переменной в подклассе. Вы должны выполнить инициализацию во время выполнения, например, в конструкторах. – aioobe

+0

@aioobe, +1, вы также можете сказать, что невозможно переопределить/переопределить любое поле вообще (статическое или нет) –

3

Есть ли конкретная причина, вы хотите, чтобы атрибут статичным? В Java типичный способ вы могли бы сделать это, чтобы иметь содержит защищенный переменный, которую затем установить в конструкторах 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), вы» d объявите функцию, которую вы можете переопределить, чтобы вернуть значение вместо использования переменной-члена.

+0

Я просто не хочу писать много раздутого кода, который делает такую ​​простую вещь (Код Python для той же функциональности действительно компактен). Статическая инициализация идеальна, потому что она чистая, и я предпочел бы ее скрывать в конструкторе (и писать специальные конструкторы для каждого подкласса). – user480884

1

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

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

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

Я хотел бы избежать повторения этого кода геттера в обоих классах. – user480884

0

Этот способ сделать это вводит в небольшое вторжение, как я мог думать. 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()); 
    } 
} 
Смежные вопросы