1 2 Previous Next 20 Replies Latest reply: May 31, 2011 7:26 AM by EJP RSS

    Static fields and inheritance

    809141
      I imagine this sort of question has been asked and answered a number of times on this forum, but I can't seem to find a definitive solution to my particular problem, so here goes.

      Let's say I have a class called "Animal," and that, in my program, there are two types of Animals, a Horse and a Cow, which extend the Animal class. Of course, I put dynamic fields and methods common to both in the parent class (Weight, Age, Gender, etc.). But what about static fields common to both? For instance, let's say all my cows eat hay, and all my horses eat oats (apologies to any farmers on the forum). I have a method that feeds each animal in the corral, and it shouldn't have to know what kind of feed the animal needs. I want to create an Animal, and use it as an iterator, calling Animal.Feed() for each object in the collection.

      Confronted with this problem, my first thought is to create a static field in Animal called "feedType," which would be inherited by Horse and Cow. A routine loads a configuration file that specifies the type of feed for each Animal: Horse.feedType = "Oats", etc. Does this, in fact, work, or does it cause problems? Is it bad practice, as some seem to think? Is there a better way, perhaps using interfaces? Any and all input would be much appreciated.
        • 1. Re: Static fields and inheritance
          sabre150
          Nothing you have described needs a static field. Your scenario is the basic requirement for overriding methods. All you need is the Animal class to have an abstract method getFeedType() that when overridden in the concrete classes and returns the feed type. You don't even need have a field to hold this. For example
          class Horse extends Animal
          {
              public String getFeedType()
              {
                  return "Oats";
              } 
          }
          class Cow extends Animal
          {
              public String getFeedType()
              {
                  return "Grass";
              } 
          }
          • 2. Re: Static fields and inheritance
            796440
            javadecaf wrote:
            I imagine this sort of question has been asked and answered a number of times on this forum, but I can't seem to find a definitive solution to my particular problem, so here goes.

            Let's say I have a class called "Animal," and that, in my program, there are two types of Animals, a Horse and a Cow, which extend the Animal class. Of course, I put dynamic fields and methods common to both in the parent class (Weight, Age, Gender, etc.). But what about static fields common to both? For instance, let's say all my cows eat hay, and all my horses eat oats (apologies to any farmers on the forum). I have a method that feeds each animal in the corral, and it shouldn't have to know what kind of feed the animal needs. I want to create an Animal, and use it as an iterator, calling Animal.Feed() for each object in the collection.
            If you want runtime polymorphism, you must use a non-private, non-static, non-final method. That's the only thing that's runtime-polymorphic in Java. Nothing private, static, or final is, and only methods are, never variables.

            So you need a
            public class Animal {
              public abstract void feed();
            }
            method.

            As for not wanting to repeat the food for each instance of Cow, since all Cows eat the same thing, you could do something like this:
            public class Cow extends Animal {
              private static final String FOOD = "hay"; // an actual Food class would be better, but one thing at a time
            
              public void feed() {
                // do stuff with Cow.FOOD
              }
            }
            You could take it a step further:
            public class Animal {
              protected abstract String getFood();
            
              public void feed() {
                String food = getFood();
                // do stuff with food
              }
            }
            
            
            public class Cow extends Animal {
              private static final String FOOD = "hay"; // an actual Food class would be better, but one thing at a time
            
              protected void getFood() {
                return Cow.FOOD;
              }
            }
            The second case is useful if a) A reasonable common default feed() behavior is getFood() and then do the same thing with the food, regardless of the type of Animal, or b) getFood() might be useful in other contexts. Other animals that have more complex or different eating behaviors can still override feed(), of course.
            Confronted with this problem, my first thought is to create a static field in Animal called "feedType," which would be inherited by Horse and Cow. A routine loads a configuration file that specifies the type of feed for each Animal: Horse.feedType = "Oats", etc. Does this, in fact, work, or does it cause problems? Is it bad practice, as some seem to think? Is there a better way, perhaps using interfaces? Any and all input would be much appreciated.
            Having a static field that specifies a constant for a class is reasonable. Note, however, that that static field cannot be overridden. There will be no runtime polymorphism on that field.

            Edited by: jverd on May 17, 2011 11:26 AM
            • 3. Re: Static fields and inheritance
              YoungWinston
              javadecaf wrote:
              Confronted with this problem, my first thought is to create a static field in Animal called "feedType," which would be inherited by Horse and Cow.
              I don't want to repeat all the good advice previously given, so I will just say this:
              avoid static fields unless they are constants
              at least until you've got a bit further. There are reasons to have non-constant fields that are static, but they're relatively rare.

              For now, I'd make it a beginner's mantra:
              * All instance fields should be private
              * All static fields should be constants (ie, they should be final )
              You'll find out when you can break it later on.

              Static methods on the other hand; quite a different kettle of fish...

              Winston
              • 4. Re: Static fields and inheritance
                809141
                @jverd & @sabre150 - Thank you both for your help. I'm always impressed by the speed and quality of the answers I get on this forum!

                I think the main thing I was missing was the technique of using abstract methods, which both of you suggested. I had previously used an interface, but when I myself writing duplicate methods, it seemed logical to switch over to a super-class, and I couldn't figure out how to re-create interface-like methods in that context. I have re-structured my real-world program (which, by the way, has nothing to do with cows) and I think I've got it right.

                There are a couple of points on which I'm still not clear, though. First, I'm not sure I understand the difference (if there is a difference) between inheritance and polymorphism:
                jverd wrote:
                If you want runtime polymorphism, you must use a non-private, non-static, non-final method. That's the only thing that's runtime-polymorphic in Java. Nothing private, static, or final is, and only methods are, never variables.
                But variables (or properties or fields, which I understand to be the same thing) can be inherited, correct? Going back to the example, if I have:
                class Animal {
                  public int weight;
                }
                
                class Cow extends Animal {
                
                public void setWeight(int weightParam) {
                  this.weight = weightParam;
                }
                and I then create a new Cow and call myCow.setWeight(1000), the result will be that myCow.weight will be set to 1000 - correct? (I know this is really basic, but I'm trying to get the concept clear).

                On the other hand, if I have:
                class Animal {
                  public static int numberOfFeet;
                }
                
                class Cow extends Animal {
                
                public void setNumberOfFeet(int numberOfFeetParam) {
                  Cow.numberOfFeet = numberOfFeetParam;
                }
                the result of calling MyCow.setNumberOfFeet(4) would be - what? Am I actually setting Animal.numberOfFeet here?

                My understand of object inheritance has always been that the primary purpose was to promote reuse of code (and, collaterally, to save programming labor). It was for this reason that was trying to use an inherited static field; since every Animal has a Food, it seemed to make sense to create it as a property of Animal, just like you would for Weight, rather than creating it individually in each sub-class. So is it just that static properties cannot be inherited by definition, or is my understanding of inheritance wrong to begin with?

                (You've already been very helpful, and I don't mean to ask for a mini-course in OOP, so if this question is too much of a mouthful, perhaps you could point me to some concise, relevant documentation on the subject.)

                Thanks again!
                • 5. Re: Static fields and inheritance
                  796440
                  javadecaf wrote:
                  I think the main thing I was missing was the technique of using abstract methods, which both of you suggested. I had previously used an interface,
                  Which is no different than using abstract methods. Not sure where your confusion lies here.
                  There are a couple of points on which I'm still not clear, though. First, I'm not sure I understand the difference (if there is a difference) between inheritance and polymorphism:
                  jverd wrote:
                  If you want runtime polymorphism, you must use a non-private, non-static, non-final method. That's the only thing that's runtime-polymorphic in Java. Nothing private, static, or final is, and only methods are, never variables.
                  But variables (or properties or fields, which I understand to be the same thing) can be inherited, correct? Going back to the example, if I have:
                  Inheritance is when something that's present in the parent is present and accessible in the child, just by virtue of the fact that the parent-child relationship exists.

                  Polymorphism literally means "many shapes", and in general it's when something with the same name behaves differently. Some say that method overloading (which is a 100% compile-time construct) is a form of polymorphism. Others say it's not. I'm in the "is" camp. Operator overloading is another form of polymorphism.

                  I was previously speaking specifically about runtime polymorphism. That is, when behavior is determined at runtime by the concrete class of the object, not at compile-time by the reference type. The only case in which this happens in Java is when determining which class's implementation of a non-private, non-static, non-final method to invoke. (Note that the method can be final in the leaf class, but then it won't have been final in a parent type, which is how we got the runtime polymorphism in the fist place.)

                  Static methods are inherited. Member variables, both static and non-static are inherited. None of these are runtime-polymorphic, however.
                  My understand of object inheritance has always been that the primary purpose was to promote reuse of code (and, collaterally, to save programming labor)
                  A common fallacy.

                  The primary purpose is type specialization. Shared code is a side benefit, but it's not the main purpose. If all you want is code reuse, [url http://www.google.com/search?q=prefer+composition+over+inheritance]prefer composition over inheritance.
                  • 6. Re: Static fields and inheritance
                    809141
                    jverd wrote:
                    javadecaf wrote:
                    I think the main thing I was missing was the technique of using abstract methods, which both of you suggested. I had previously used an interface,
                    Which is no different than using abstract methods. Not sure where your confusion lies here.
                    There was no confusion on this point; I'm sorry if I didn't make that clear.
                    Static methods are inherited. Member variables, both static and non-static are inherited. None of these are runtime-polymorphic, however.
                    I think I understand now what you mean by runtime polymorphism. It seems to me, though, that it would be possible to achieve a kind of "fake polymorphism" by hiding fields - is that correct? (I'm aware that this is considered bad practice, and I don't plan to do it, but this is just for the sake of understanding the concept.) For example, I could have a static member variable in the child that hides a member variable in the parent by using the same name, causing a different property to be returned at runtime based on the class of the object in question.

                    On the other hand, if I simply use the inherited static property, it would point to the parent class, not the child, correct? This would be because static properties are properties of the class itself, not the object.
                    My understand of object inheritance has always been that the primary purpose was to promote reuse of code (and, collaterally, to save programming labor)
                    A common fallacy.

                    The primary purpose is type specialization. Shared code is a side benefit, but it's not the main purpose. If all you want is code reuse, [url http://www.google.com/search?q=prefer+composition+over+inheritance]prefer composition over inheritance.
                    We've been over this ground before (previous post last year on a slightly different subject) and I'm happy to say I understand the concept better than I did last time. The question I ask myself is, "Is object A a special type of object B, implementing all the methods and properties of B, plus others unique to A?" If the answer is yes, I go for inheritance. I guess that's not a particularly deep analysis, but it seems generally in line with the principles of good OOP.
                    • 7. Re: Static fields and inheritance
                      809141
                      @Winston - thanks for the additional input. The reason I was trying to use a non-constant static field was that I wanted it to be set by a separate method that loads a configuration file. Perhaps there is a way to do this using final, but I don't know what it is. Or, this could be one of those "rare situations" where it's actually required...
                      • 8. Re: Static fields and inheritance
                        796440
                        javadecaf wrote:
                        jverd wrote:
                        Static methods are inherited. Member variables, both static and non-static are inherited. None of these are runtime-polymorphic, however.
                        I think I understand now what you mean by runtime polymorphism. It seems to me, though, that it would be possible to achieve a kind of "fake polymorphism" by hiding fields - is that correct? (I'm aware that this is considered bad practice, and I don't plan to do it, but this is just for the sake of understanding the concept.) For example, I could have a static member variable in the child that hides a member variable in the parent by using the same name, causing a different property to be returned at runtime based on the class of the object in question.
                        Nope. Try it and see.
                        class P {
                          public static String v = "P";
                        
                          public String getV() {
                            return v;
                          }
                        }
                        
                        class C  extends P {
                          public static String v = "C";
                        }
                        
                        public class Main {
                          public static void main(String[] args) {
                            P p1 = new P();
                            P p2 = new C();
                            P p3 = null;
                        
                            System.out.println(p1.v);
                            System.out.println(p2.v);
                            System.out.println(p3.v); // note no NPE
                            
                            System.out.println();
                            System.out.println(p1.getV());    
                            System.out.println(p2.getV());    
                            //System.out.println(p3.getV());    // NPE, but no NPE if getV() were static
                          }
                        }
                        My understand of object inheritance has always been that the primary purpose was to promote reuse of code (and, collaterally, to save programming labor)
                        A common fallacy.

                        The primary purpose is type specialization. Shared code is a side benefit, but it's not the main purpose. If all you want is code reuse, [url http://www.google.com/search?q=prefer+composition+over+inheritance]prefer composition over inheritance.
                        We've been over this ground before (previous post last year on a slightly different subject) and I'm happy to say I understand the concept better than I did last time. The question I ask myself is, "Is object A a special type of object B, implementing all the methods and properties of B, plus others unique to A?" If the answer is yes, I go for inheritance.
                        Not even "plus others". Usually it just implements some of the existing ones differently, or implements abstract ones that the parent doesn't. It's fairly uncommon to extend concrete classes.
                        • 9. Re: Static fields and inheritance
                          796440
                          javadecaf wrote:
                          @Winston - thanks for the additional input. The reason I was trying to use a non-constant static field was that I wanted it to be set by a separate method that loads a configuration file. Perhaps there is a way to do this using final, but I don't know what it is. Or, this could be one of those "rare situations" where it's actually required...
                          private static final String FOO = loadFromConfigFile();
                          
                          // or, if that load method can throw an unchecked exception, or requires other setup first, or post-processing
                          
                          private static final String FOO;
                          
                          // static initializer block
                          static {
                            try {
                              // do necessary pre-load work
                              String temp = loadFromConfigFile();
                              FOO = post_process(temp);
                            }
                            catch (IOException e) {
                              throw new ExceptionInInitializerError(e);
                            }
                          }
                          • 10. Re: Static fields and inheritance
                            809141
                            Wow - fascinating. As you can see, I have a lot to learn, but you're helping me a great deal. Since the configuration file contains variables that need to be assigned to several different classes, would you call the method that reads it individually in each one? Or is there a way to read those values all at once into a static array attached to the main method, where the initialization blocks could pull them out? My concern with the latter approach is that I have no idea in what order the classes are "constructed" (for lack of a better word) at runtime. Either approach seems like it might involve the program doing unnecessary duplicate tasks, but maybe there's a better way I haven't thought of (chances are...)
                            • 11. Re: Static fields and inheritance
                              796440
                              Here's one possible approach:
                              public class Cow {
                                private static final String foodName; // "hay"
                              
                                static {
                                  try {
                                    foodName = AnimalUtil.getFoodName(Cow.class);
                                  }
                                  catch (...) {
                                    ...
                                  }
                              }
                              AnimalUtil reads the file and stores a map of classname --> foodName.
                              • 12. Re: Static fields and inheritance
                                809141
                                OK, that makes sense, but how can we be sure that AnimalUtil will have read the file and be ready with the map before the initialization block runs on Cow? Or are you imagining a construction of getFoodName that opens the file each time it's called? If so, then we're back opening the file multiple times.
                                • 13. Re: Static fields and inheritance
                                  796440
                                  javadecaf wrote:
                                  OK, that makes sense, but how can we be sure that AnimalUtil will have read the file and be ready with the map before the initialization block runs on Cow?
                                  Well, Cow calls that AnimalUtil method. So one of the following:

                                  1) The getFoodName() method explicitly reads the file every time it's called.

                                  2) The AU class has a didIReadTheConfigFileYet flag, and getFoodName() causes the file to be read if the flag hasn't been set yet.

                                  3) AU has its own static initializer that reads the file. When our program refers to AU for the first time from (like form Cow's static init block), that causes AU to be loaded, which causes AU's static init to run, which reads the file.
                                  Or are you imagining a construction of getFoodName that opens the file each time it's called? If so, then we're back opening the file multiple times.
                                  So? How often are you picturing reading that file? So far it's only read whenever we first load a new Animal subclass. You can read thousands or millions or lines per second. Reading a config file multiple times isn't necessarily a bad thing.

                                  First make it work. Then worry about making it faster. If needed.
                                  • 14. Re: Static fields and inheritance
                                    809141
                                    Great advice and information. I'm sure I'll be referring to this thread quite a bit in the future. Thanks again for all your help!
                                    1 2 Previous Next