Avoid calling non-final methods in a constructor: Applies to static methods too?

Discussion in 'Java' started by Oliver Wong, Jun 7, 2006.

  1. Oliver Wong

    Oliver Wong Guest

    I'm aware of and follow the dogma that one should not call non-final
    methods in a constructor. However, I'm wondering whether this applies to
    static methods as well. My understanding of the reasoning behind this rule
    is that subclasses may see fields in some unstable state, which tells me
    that the rule need not apply to static methods. However, this code analysis
    tool is reporting a warning with the following code:

    <code>
    public class Test {
    public Test() {
    staticMethod();
    }

    public static void staticMethod() {
    //Does nothing.
    }
    }
    </code>

    Should I be declaring the staticMethod as being final? Will that even
    have any effect on the semantics of the code? Or should I rather submit this
    as a potential bug fix to the tools author?

    - Oliver
    Oliver Wong, Jun 7, 2006
    #1
    1. Advertising

  2. Oliver Wong

    Chris Uppal Guest

    Oliver Wong wrote:

    > <code>
    > public class Test {
    > public Test() {
    > staticMethod();
    > }
    >
    > public static void staticMethod() {
    > //Does nothing.
    > }
    > }
    > </code>
    >
    > Should I be declaring the staticMethod as being final? Will that even
    > have any effect on the semantics of the code? Or should I rather submit
    > this as a potential bug fix to the tools author?


    Final doesn't apply to static methods 'cos they don't override anyway (I don't
    suppose Java will even let you combine the two, though I haven't tested it).
    Unless the linting tool is just warning you about calling static methods /at
    all/ (which seems a touch too sweeping even for my taste ;-) or -- more
    likely -- warning you about calling a static method via an instance referrence
    (in this case the implicit "this."), then I think it must be a bug.

    -- chris
    Chris Uppal, Jun 7, 2006
    #2
    1. Advertising

  3. Oliver Wong

    Piotr Kobzda Guest

    Re: Avoid calling non-final methods in a constructor: Applies tostatic methods too?

    Oliver Wong wrote:

    > Should I be declaring the staticMethod as being final? Will that even
    > have any effect on the semantics of the code?


    The only benefit of using final static method is to prevent against
    declaration of another static method with the same signature in a
    subclasses, no other semantical consequences holds. In other words
    static methods are always called in static way, that is using
    invokestatic bytecode instruction (invokevirtual or invokespecial are
    never used for static methods).

    > Or should I rather submit
    > this as a potential bug fix to the tools author?


    I think you should.


    Regards,
    piotr
    Piotr Kobzda, Jun 7, 2006
    #3
  4. "Chris Uppal" <-THIS.org> wrote in message
    news:4486fcb1$0$657$...

    >
    > Final doesn't apply to static methods 'cos they don't override anyway (I
    > don't
    > suppose Java will even let you combine the two, though I haven't tested
    > it).
    > Unless the linting tool is just warning you about calling static methods
    > /at
    > all/ (which seems a touch too sweeping even for my taste ;-) or -- more
    > likely -- warning you about calling a static method via an instance
    > referrence
    > (in this case the implicit "this."),


    Are you saying that in

    void meth()
    {
    staticMethod();
    }

    static void meth2()
    {
    staticMethod();
    }

    static void staticMethod()
    {
    }

    the first call to staticMethod() is done implicitly via "this" and while the
    second call simply finds that staticMethod() is in scope? I am dubious :)

    > then I think it must be a bug.
    Mike Schilling, Jun 7, 2006
    #4
  5. Oliver Wong

    Chris Uppal Guest

    Mike Schilling wrote:

    > Are you saying that in
    >
    > void meth()
    > {
    > staticMethod();
    > }
    >
    > static void meth2()
    > {
    > staticMethod();
    > }
    >
    > static void staticMethod()
    > {
    > }
    >
    > the first call to staticMethod() is done implicitly via "this" and while
    > the second call simply finds that staticMethod() is in scope? I am
    > dubious :)


    I'm by no means certain which of the two candidate "explanations" apply from
    the JLS. I suspect that both apply. But it doesn't really matter -- the
    question is whether Oliver's linting tool interpreted it like that.

    BTW, I did try putting
    static final void aMethod() {}
    into a class and javac accepted it quite happily -- which strikes me as stupid.
    So then I tried Piotr's suggestion -- that it prevents you from creating
    another static method with the same name/signature in a subclass -- and he's
    right. I think that's /really/ stupid...

    -- chris
    Chris Uppal, Jun 7, 2006
    #5
  6. Oliver Wong

    Piotr Kobzda Guest

    Re: Avoid calling non-final methods in a constructor: Applies tostatic methods too?

    Chris Uppal wrote:

    > So then I tried Piotr's suggestion -- that it prevents you from creating
    > another static method with the same name/signature in a subclass -- and he's
    > right. I think that's /really/ stupid...


    Not as stupid as it looks like, IMHO. ;)

    Formally there are adequate paragraphs in JSL which explains why this
    construct is allowed, in particular see 8.4.3.2, 8.4.3.3 and 8.4.8.2 (JLS3).

    I've not based any solution on final static methods yet, but I can
    imagine some potential usages of such kind of methods.

    Having for example:

    class A {
    static final void m1() {}
    }
    class B extends A {
    }

    we can call A's class m1 method with:

    A.m1();

    or (what is a key here) with:

    B.m1();


    This is of course not any special property of final static methods
    (non-final static methods can be invoked the same way). But thanks to a
    final there is no possibility to hide our A's m1 method from any class
    subclassing A (e.g. from B).

    So using final static methods we can create a special methods (e.g.
    factory, registration, authentication etc.). And we know that nowhere in
    our class hierarchy is a method accidentally (or not) "replacing" our
    method's functionality.

    Of course, as I said before, all static methods calls are preformed in a
    static way (that means methods lookup is performed in compile time
    only). So even when we'll make A's m1 method non-final, and than add
    method hiding it to class B, our both above example calls will still
    call A's m1 until we do not recompile them again.


    Regards,
    piotr
    Piotr Kobzda, Jun 7, 2006
    #6
  7. Oliver Wong

    Chris Smith Guest

    Piotr Kobzda <> wrote:
    > Chris Uppal wrote:
    >
    > > So then I tried Piotr's suggestion -- that it prevents you from creating
    > > another static method with the same name/signature in a subclass -- and he's
    > > right. I think that's /really/ stupid...

    >
    > Not as stupid as it looks like, IMHO. ;)


    Nah, it's definitely stupid. It assigns yet another completely new
    meaning to final, which is only superficially similar to the existing
    meaning for instance methods.

    --
    Chris Smith - Lead Software Developer / Technical Trainer
    MindIQ Corporation
    Chris Smith, Jun 7, 2006
    #7
  8. Oliver Wong

    Piotr Kobzda Guest

    Re: Avoid calling non-final methods in a constructor: Applies tostatic methods too?

    Chris Smith wrote:
    > Piotr Kobzda <> wrote:
    >> Chris Uppal wrote:
    >>
    >>> So then I tried Piotr's suggestion -- that it prevents you from creating
    >>> another static method with the same name/signature in a subclass -- and he's
    >>> right. I think that's /really/ stupid...

    >> Not as stupid as it looks like, IMHO. ;)

    >
    > Nah, it's definitely stupid. It assigns yet another completely new
    > meaning to final, which is only superficially similar to the existing
    > meaning for instance methods.


    Completely new meaning? That meaning is given to final at the beginning
    of Java (check JLS first! ed.). Using final methods (8.4.3.3) prevents
    us from _overriding_ (8.4.8.1) of instance methods or _hiding_ (8.4.8.2)
    of static methods. Which in fact gives *very similar* meaning to final
    in both cases, it simply prevents from providing a "new version" of
    method in subclasses.
    What's stupid in that?


    Regards,
    piotr
    Piotr Kobzda, Jun 8, 2006
    #8
  9. Oliver Wong

    Chris Uppal Guest

    Piotr Kobzda wrote:

    > Completely new meaning? That meaning is given to final at the beginning
    > of Java (check JLS first! ed.). Using final methods (8.4.3.3) prevents
    > us from _overriding_ (8.4.8.1) of instance methods or _hiding_ (8.4.8.2)
    > of static methods. Which in fact gives *very similar* meaning to final
    > in both cases, it simply prevents from providing a "new version" of
    > method in subclasses.
    > What's stupid in that?


    Well, I'm still sticking by the word "stupid". In this particular case it's
    conflating two notions which are a lot less closely related than they might
    look to a beginner. That's confusing for beginners, and irritating for purists
    (and are there any other categories of programmer I care about ? Hmm.... ;-)

    More generally, it's part-and-parcel with the mess surrounding static method in
    Java. It's not the static methods themselves that I object to (though I don't
    think they are done right), but all sorts of silly little details in the spec,
    and so on, give the (IMO very strong) impression that the Java designers simply
    didn't understand the difference between static methods (more properly called
    functions), and real (OO) methods. My three favourite examples.

    1 (the famous one) You can invoke a static method "via" a reference to an
    instance.

    2 The recommended order of keywords gives access control primacy over the
    static/non-static distinction, when it is /much/ less important.

    3) The method resolution rules in the JVM /require/ that the JVM first finds
    the method with the given name/signature, and only /after/ it has done that is
    it allowed to check whether the discovered method is static or not (and to
    throw an error if its of the wrong kind) -- even though invokestatic and
    invokevirtual (and variants) are not interchangeable instructions.

    I get the impression that the designers had some sort of fuzzy idea of "static"
    members being somehow shared between all the instances. And that -- above
    all -- strikes me as stupid.

    -- chris
    Chris Uppal, Jun 8, 2006
    #9
  10. Oliver Wong

    Chris Smith Guest

    Piotr Kobzda <> wrote:
    > Chris Smith wrote:
    > > Nah, it's definitely stupid. It assigns yet another completely new
    > > meaning to final, which is only superficially similar to the existing
    > > meaning for instance methods.

    >
    > Completely new meaning? That meaning is given to final at the beginning
    > of Java (check JLS first! ed.). Using final methods (8.4.3.3) prevents
    > us from _overriding_ (8.4.8.1) of instance methods or _hiding_ (8.4.8.2)
    > of static methods.


    Indeed, and the part about "hiding" of static methods is new versus a
    hypothetical language where it is illegal to use the final modifier on a
    static method. That hypothetical language is more consistent and
    predictable than Java, hence the adjective "stupid" attached to the
    choice to allow final on static methods.

    > Which in fact gives *very similar* meaning to final
    > in both cases,


    I don't think it's very similar at all. In one case, you are prevented
    from redefining the behavior of existing code by changing the behavior
    for an existing method when executed in the context of a subclass. In
    the other place, you are prevented from using a certain identifier to
    define a completely new and unrelated static method in a subclass. The
    fact that these two entirely different things look similar is confusing
    and counts as a fault in the language. Why would anyone want to define
    a language feature as if to pretend that they really are similar, and
    thus further the confusion?

    --
    Chris Smith - Lead Software Developer / Technical Trainer
    MindIQ Corporation
    Chris Smith, Jun 8, 2006
    #10
  11. Oliver Wong

    Chris Smith Guest

    Chris Smith <> wrote:
    > I don't think it's very similar at all. In one case, you are prevented
    > from redefining the behavior of existing code by changing the behavior
    > for an existing method when executed in the context of a subclass.


    Okay, so that was a little awkward. It can be cleaned up a little by
    using more theoretical OO technology.

    In one case, you are prevented from redefining the behavior of existing
    code by changing the method by which an object of the subclass responds
    to the same message. In the other place, you are prevented from
    defining essentially a new message with the same name as the existing
    message.

    --
    Chris Smith - Lead Software Developer / Technical Trainer
    MindIQ Corporation
    Chris Smith, Jun 8, 2006
    #11
  12. "Chris Smith" <> wrote in message
    news:...
    > Chris Smith <> wrote:
    >> I don't think it's very similar at all. In one case, you are prevented
    >> from redefining the behavior of existing code by changing the behavior
    >> for an existing method when executed in the context of a subclass.

    >
    > Okay, so that was a little awkward. It can be cleaned up a little by
    > using more theoretical OO technology.
    >
    > In one case, you are prevented from redefining the behavior of existing
    > code by changing the method by which an object of the subclass responds
    > to the same message. In the other place, you are prevented from
    > defining essentially a new message with the same name as the existing
    > message.


    That's the point, I think. There is no relationship between the two methods
    defined in

    class Super{ public static void a() {}}
    class Sub extends Super {public static void a() {} }

    except that they have the same name. One hides the other, but that's quite
    different from overriding it.
    Mike Schilling, Jun 8, 2006
    #12
  13. Oliver Wong

    Dale King Guest

    Re: Avoid calling non-final methods in a constructor: Applies tostatic methods too?

    Oliver Wong wrote:
    > I'm aware of and follow the dogma that one should not call non-final
    > methods in a constructor. However, I'm wondering whether this applies to
    > static methods as well. My understanding of the reasoning behind this
    > rule is that subclasses may see fields in some unstable state, which
    > tells me that the rule need not apply to static methods. However, this
    > code analysis tool is reporting a warning with the following code:


    That dogma is a little overstated. You do need to be careful when
    calling non-final instance methods, but saying that you should never
    call non-final methods goes a bit too far. The more precise rule is that
    you should not call non-final methods whose implementations depend on
    the instance state.

    For example, I have no problem with code that calls methods that depend
    only on constants. But the problem is there is no way to force that from
    the superclass. It would be nice if there were an annotation to force
    subclasses to not use instance state in a method.

    --
    Dale King
    Dale King, Jun 11, 2006
    #13
  14. Oliver Wong

    Piotr Kobzda Guest

    Re: Avoid calling non-final methods in a constructor: Applies tostatic methods too?

    Piotr Kobzda wrote:

    > Having for example:
    >
    > class A {
    > static final void m1() {}
    > }
    > class B extends A {
    > }
    >
    > we can call A's class m1 method with:
    >
    > A.m1();
    >
    > or (what is a key here) with:
    >
    > B.m1();
    >


    Heaving the above example the following description is not quite true...

    > Of course, as I said before, all static methods calls are preformed in a
    > static way (that means methods lookup is performed in compile time
    > only). So even when we'll make A's m1 method non-final, and than add
    > method hiding it to class B, our both above example calls will still
    > call A's m1 until we do not recompile them again.


    We don't have to recompile it again to see a different results -- that's
    my earlier intuitive feeling on how static final methods are treated by
    the compiler.
    I've checked resulting bytecode, and invokestatic B.m1() still exists
    for the above last usage example.
    Nevertheless B.m1() results in A.m1() invocation at runtime. That is
    because of Java method resolution mechanism, which is common for both
    static and instance methods (see JVMS 2nd ed. - 5.4.3.3 Method Resolution).

    Thus we have a kind of dynamic lookup of static methods within class
    hierarchy (starting class B in my example) -- similar to the lookup
    performed during invokespecial instruction calls.


    Backing to the discussion on meaning of final for static methods, I'm
    still the one -- having respect to all opinions given here -- for whom
    using it makes some sense, final simply gives us an ability to tell the
    others: "don't care about hidings of this method" and that's all for me.


    Regards,
    piotr
    Piotr Kobzda, Jun 12, 2006
    #14
  15. Oliver Wong

    Chris Uppal Guest

    Re: Avoid calling non-final methods in a constructor: Applies to static methods too?

    Piotr Kobzda wrote:

    > Thus we have a kind of dynamic lookup of static methods within class
    > hierarchy (starting class B in my example) -- similar to the lookup
    > performed during invokespecial instruction calls.


    Yes. The JVM-level static method lookup is distinctly strange, and it has
    definite resemblances to virtual method lookup. I have always considered this
    to be a mix of (a) a sensible strategy to ensure binary compatibility as static
    members are migrated around the class hierarchy, and -- less importantly -- (b)
    another example of the arbitrary weirdness surrounding static members in Java.


    > Backing to the discussion on meaning of final for static methods, I'm
    > still the one -- having respect to all opinions given here -- for whom
    > using it makes some sense, final simply gives us an ability to tell the
    > others: "don't care about hidings of this method" and that's all for me.


    Fair enough. I wasn't disputing your facts (indeed, I learned from you here);
    and what's left is a value judgement and/or a question of interpretation. If,
    as it seems to you, this feature is reasonably consistent or otherwise a good
    design choice, then who can say you are wrong ? I, personally, disagree (and
    it seems that Chris Smith does too -- we Chrises stick together), but
    presumably a certain J Gosling would agree with your interpretation ;-)

    -- chris
    Chris Uppal, Jun 13, 2006
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. JFCM
    Replies:
    4
    Views:
    5,724
  2. Replies:
    5
    Views:
    505
    Chris Uppal
    Nov 17, 2006
  3. Ricardo Palomares Martinez
    Replies:
    2
    Views:
    368
    david.karr
    Apr 28, 2007
  4. Generic Usenet Account
    Replies:
    10
    Views:
    2,204
  5. puzzlecracker
    Replies:
    2
    Views:
    462
    Daniel Pitts
    Jul 25, 2008
Loading...

Share This Page