Re: getting used to Java - question about "style"

From: Chris Gray (chris.gray_at_kiffer.be)
Date: 07/06/04


Date: Tue, 06 Jul 2004 22:15:13 +0200

glunk wrote:

> I am working on my very first Java project. I have been familiar with OO
> design for a long time. But I have never put the real thing into practice
> (formerly a VB 6 programmer which only buys you encapsulation). My company
> is shifting away from VB / ASP solutions and bringing in Java and JSP. I
> am one of the ground breakers (God help me).
>
> I am reading a book that a collegue gave me called "The Elements of Java
> Style" by Vermeulen, Ambler, Bumgardner, Metz, Misfeldt, Shur and
> Thompsaon. (A lot of authors for a really skinny book.) Anyway, ONE OF THE
> RULES THAT THEY HAVE IS
>
> "Do not call nonfinal methods from within a constructor."
>
> They go on to explain
>
> "Subclasses may override nonfinal methods and Java will dispatch a call to
> such a mrethod according to the actual type of the constructed object -
> before executing the derived class constructors. This means when the
> constructor invokes the derived method, the derived class may be in an
> invalid state. To prevent this, call only final methods from the
> constructor."
>
> I cannot understand what this says or means. I know that a final method is
> one that cannot be overridden. I do not understand what this parapgraph is
> intending to warn me against doing or why. Can someone explain, preferably
> with an example?

I'll try.

Let's suppose you create a class Foo ...
  public class Foo {

and that there is some work which you need to do in various constructors,
maybe in some methods too, so you bundle it into a method frob() ...

    public Foo() {
      frob();
    }

    public Foo(String s) {
      // do somethig with s ...
      frob();
    }

    void frob() {
      // set up some stuff somewhere
    }

    // etc
  }

Now suppose someone extends Foo. They add some new fields, which are
initialised in the subclass's constructors, or maybe in an initialiser.

  public class Bar extends Foo {
    private static next_seq_no;
    private int seq_no = ++next_seq_no;
    private String name = "Bar" + seq_no;
  ...

They can also override frob(), because we didn't make it private or final.
Now the fun starts. :)

When a new object of type Bar is created, the first thing that happens
(after allocating memory for the object) is that a constructor of Foo is
called. If the author of Bar didn't specify a constructor at all then one
will be generated automatically by the compiler:
    public Bar() {
      super();
    }
Or the author of Bar could call Foo's constructor explicitly; for example
    public Bar(String s) {
      super(s);
      ...
    }

In either case, the constructor of Foo will be called before any Bar code is
executed, including the initializers of seq_num and name. During the call
to the Foo constructor seq_num will be zero and name will be null.

Now look at what happens when the Foo constructor calls frob(). Which frob()
gets called? The one declared in Bar of course, because it is being called
on an object of type Bar. Did the programmer of Bar expect her frob() to be
called with seq_num equal to zero and name equal to null? No she didn't,
because she carefully wrote initialisers for both those variables.

This kind of confusion can be avoided by only calling methods from inside a
constructor if they are either private, or final, or static. (So the text
you quote is too restrictive).

HTH
 

-- 
Chris Gray      chris@kiffer.eunet.be
/k/ Embedded Java Solutions


Relevant Pages

  • Re: C++ design question
    ... so anyone can instantiate it without ... > default constructor in the class header rather that allowing it to be ... > separately and initialize a pointer to it in Foo: ... fooDeriveN::DoStuffWithBarBase() at all because we have a Bar* in Foo*. ...
    (comp.object)
  • Re: Why cant I call a parameterless-constructor from a baseclass ?
    ... public class foo ... public class bar: foo ... constructor for bar that takes an int, ... not specify any constructor at all for a class, ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: C++ design question
    ... The default constructor is implied in the initialization list. ... One wants to access Bar at the superclass level to avoid static typing ... Usually that would be done by whoever instantiates a Foo subclass ...
    (comp.object)
  • Re: Disadvantages of Inheritance, Polymorphism and Encapsulation
    ... Bar, in return, should not surprise Foo. ... > into Frob(), and vice versa. ...
    (comp.object)
  • Re: Creating an object that is read from an input stream.
    ... You can use the copy constructor to implement operator>> like so: ... Foo foo; ... Bar bar; ... // use new class MyClass that has a MyClass_base pointer ...
    (comp.lang.cpp)