Java Forum / General / June 2006
Avoid calling non-final methods in a constructor: Applies to static methods too?
Oliver Wong - 07 Jun 2006 17:09 GMT 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
Chris Uppal - 07 Jun 2006 17:20 GMT > <code> > public class Test { [quoted text clipped - 11 lines] > 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
Mike Schilling - 07 Jun 2006 18:16 GMT > Final doesn't apply to static methods 'cos they don't override anyway (I > don't [quoted text clipped - 6 lines] > 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. Chris Uppal - 07 Jun 2006 19:09 GMT > Are you saying that in > [quoted text clipped - 15 lines] > 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
Piotr Kobzda - 07 Jun 2006 22:19 GMT > 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
Chris Smith - 07 Jun 2006 23:39 GMT > > 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.
 Signature Chris Smith - Lead Software Developer / Technical Trainer MindIQ Corporation
Piotr Kobzda - 08 Jun 2006 08:25 GMT >>> 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 [quoted text clipped - 4 lines] > 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
Chris Uppal - 08 Jun 2006 15:53 GMT > 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 [quoted text clipped - 3 lines] > 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 Smith - 08 Jun 2006 16:02 GMT > > Nah, it's definitely stupid. It assigns yet another completely new > > meaning to final, which is only superficially similar to the existing [quoted text clipped - 4 lines] > 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?
 Signature Chris Smith - Lead Software Developer / Technical Trainer MindIQ Corporation
Chris Smith - 08 Jun 2006 16:06 GMT > 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.
 Signature Chris Smith - Lead Software Developer / Technical Trainer MindIQ Corporation
Mike Schilling - 08 Jun 2006 17:52 GMT >> 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 [quoted text clipped - 8 lines] > 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.
Piotr Kobzda - 12 Jun 2006 15:32 GMT > Having for example: > [quoted text clipped - 11 lines] > > 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
Chris Uppal - 13 Jun 2006 10:18 GMT > 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
Piotr Kobzda - 07 Jun 2006 17:45 GMT > 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
Dale King - 11 Jun 2006 02:08 GMT > 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.
 Signature Dale King
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|