views:

150

answers:

5

Consider the following code in Python:

class A(object):
    CLASS_ATTRIBUTE = 42

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

class B(A):
    CLASS_ATTRIBUTE = 44

Now A().f() and B().f() return "CLASS_ATTRIBUTE: 42" and "CLASS_ATTRIBUTE: 44" respectively.

How can I achieve a similar effect in Java? I want a CLASS_ATTRIBUTE field to be initialized statically and redefined in the inherited class but the f method should be only defined in the base class.

+3  A: 

Short answer: you cant solve it like this in Java. You'll have to solve it in another way.

In Java you can't override or "redeclare" fields in subclasses, and you can't override static methods.

It can be solved using an ugly reflection-hack (should be avoided though):

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;
}
aioobe
Well, I don't require the corresponding field to be static in Java. I just want to have a similar functionality without writing pages of code.
Still, you can't initialize the variable statically, and then statically "reinitialize" an instance of the variable in the sub-class. You'll have to do the initialization in runtime, in for instance the constructors.
aioobe
@aioobe, +1, you can also say that it's impossible to override/redeclare any field at all (static or not)
Colin Hebert
@Colin, good point. Updated the answer.
aioobe
Surprisingly I can have a field that is not declared as a static one but initialized in the same place where it is declared:
Hum, perhaps so, but it will not be "virtual" in the sense that it will not "override" any field in the super class.
aioobe
:/ I hit enter too early... I had something like `protected int x = 10;` in mind. And this can be redeclared in subclasses causing instances of the subclass to have 2 field with the same name.
Yes, precisely, but they will not be "looked up virtually" so to speak.
aioobe
@user480884 this is called ["hiding"](http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html#34133)
Colin Hebert
@Colin, what do you think about the reflection-hack? :-)
aioobe
@aioobe nice try but reflection is really the very last resort :)
@aioobe, I'm trying to find a solution to a small problem. What if the class declares a non-static field named CLASS_ATTRIBUTE ?
Colin Hebert
@Colin, not possible, is it? Fields aren't "virtual" in my head at least...
aioobe
@user480884, you're right of course... reflection should be avoided!
aioobe
@aioobe, Just for fun, I've done this : http://ideone.com/amHlO
Colin Hebert
@colin: looks nice :D
aioobe
+3  A: 

Is there a particular reason you want the attribute to be static? In Java the typical way you'd do this is to have A contain a protected variable that you then set in the constructors of the 2 classes:

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

Alternatively (and probably more consistent with Java design patterns) you'd declare a function that you can override to return the value instead of using a member variable.

kkress
I just don't want to write lots of bloated code that does so simple thing (Python code for the same functionality is really compact). Static initialization is perfect because it is clean and I'd prefer that over hiding it in the constructor (and writing custom constructors for every subclass).
+1  A: 

You can't do this directly with only a variable, because in Java variables cannot override (they only shadow the super classes variables).

You need to use a protected "getter" method, which can then be overridden by the subclass:

class A
{
private int attribute=42;

...

protected int getAttribute() {
    return attribute;
    }
}

class B
extends A
{
private int attribute=44;

...

protected int getAttribute() {
    return attribute;
    }
}

But note there's a special consideration to calling methods from an object's constructor, in that it allows object code to run before object construction is complete.

Software Monkey
I would like to avoid repeating this getter code in both classes.
+1  A: 

I'm not sure if you meant "statically" literally or not, but here's a brief example of how inheritance at it's most basic form looks in Java. Note that using a getter method to access the variable is a better idea for several reasons -- this is just an example.

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!

dpatch
@user480884, Wow, you shouldn't have said statically in your question.
aioobe
This one is closest to my expectations. If only I could get rid of that constructor in the subclass... At least for the base class this field is initialized statically (at least it looks so - I'm not familiar with Java to be honest).
Ah, I see......
aioobe
A: 

This way of doing it introduces as little intrusion as I could think of. setAttribute() could be named something like setDefaultValue() if that's clearer.

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());
    }
}
Stephen P