37

Out of curiosity,

Why is the finalize() method's access modifier is made as protected. Why cant it be public? Can someone explain me any specific reason behind this?

Also, I came to know that finalize() method is called only once. If I call it twice in my program internally, what is happening? Will the garbage collector call this again?

private void dummyCall() {
    try {
        finalize();
        finalize();
    } catch (Throwable e) {
        e.printStackTrace();//NOT REACHES EXCEPTION
    }
}
bragboy
  • 34,892
  • 30
  • 114
  • 171
  • 2
    why would you write a method to invoke finalize(). finalize() is invoked at instance destruction by the JVM. you should not invoke it. You can override it though, in case you want special behavior at destruction time... – harschware Feb 18 '10 at 19:21
  • Yes. I personally would never do that. But i asked it out of curiosity since I read GC wont invoke it if its already called on an object. Who is keeping track whether this finalize() method is called or not is what my doubt. I have not got a convincing explanation for this second question though. – bragboy Feb 18 '10 at 19:36
  • 1
    The real interesting question is: why is *finalize()* present at the very top of the Java OO hierarchy? 200K LOC project here and we haven't overriden *finalize()* a single time. Some would even say it's a code smell to override *finalize()* and some heretics would go as far as saying that *finalize()* doesn't exists at the OOA/OOD level and that it's presence at the top of the Java hierarchy is a (broken) Java idiosynchrasy (and completely unrelated to your problem space). Quite some of the upvoted answers here btw consider *finalize()* to be broken/flawed in one way or another :) – SyntaxT3rr0r Feb 18 '10 at 20:17
  • 1
    Only experts in Java should be going anywhere near finalize(). – Kevin Bourrillion Feb 18 '10 at 22:54
  • "GC wont invoke it if its already called on an object. Who is keeping track whether this finalize() method is called or not ..." Err, GC is keeping track? And once the object gets into the hands of tjhe GC you don't *have* a way of calling finalize() yourself. Really your question makes no sense. – user207421 Feb 19 '10 at 02:36
  • 4
    'The real interesting question is: why is finalize() present at the very top of the Java OO hierarchy?' Err, so GC can call it on any object? – user207421 Feb 19 '10 at 02:36
  • Just because you might want to call finalize() on some objects, does not mean they all need it. How about an interface and if you want the GC to call you can say `implements finalize` on your class. Also, only thing you should be able to do in finalize is log that some member variable is != null because someone didn't write the correct `finally` block. – WW. Jun 14 '11 at 11:23

9 Answers9

26

I answer your question with another question:

Why finalize method shouldn't be protected?

In general, you should try to keep things as much private as possible. That's what encapsulation is all about. Otherwise, you could make everything public. finalize can't be private (since derived classes should be able to access it to be able to override it), so it should at least be protected but why give out more access when it's not desirable?


After reading your comment more carefully, I guess I see your main point now. I think your point is since everything derives from java.lang.Object and consequently accesses its protected members, it wouldn't make any difference for it (or any method in java.lang.Object for that matter) to be public as opposed to protected. Personally, I'd count this as a design flaw in Java. This is indeed fixed in C#. The problem is not why finalize is protected. That's OK. The real issue is that you shouldn't be able to call protected methods in the base class through an object reference of the base class type. Eric Lippert has a blog entry discussing why allowing such kind of access to protected members is a bad idea which is further elaborated on Stack Overflow in this question.

Community
  • 1
  • 1
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 2
    "Hiding" as much information as possible is the essence of abstraction. – jldupont Feb 18 '10 at 19:18
  • Why not? I can call finalize() method of an instance from another instance right? Either cases, my intention is the same. So, why cant I do that? – bragboy Feb 18 '10 at 19:19
  • @Bragaadeesh: it is one of those cases where the platform can protect the programmer from himself ;-) – jldupont Feb 18 '10 at 19:20
  • @Bragaadeesh: When you declare a field, you make it private? Why? If you accessed it in another class, the intention would be identical too. – Mehrdad Afshari Feb 18 '10 at 19:20
  • 2
    Oh, that's weird. Personally i find it a weak point of java that abstract methods can't apparently be private. Anyone knows the reason? Does it have something to do with the brittle base class problem? – Johannes Schaub - litb Feb 18 '10 at 19:22
  • 7
    @Johannes: Because an abstract method *must* be overridden by a subclass, and you can't override private methods. Therefore, `private abstract` would be a contradiction in terms. – Lawrence Dol Feb 18 '10 at 19:25
  • I don't see any reason why you want to. The class declaring the private method is the only class that can use it. What would be the intended use of a private abstract method? Do you want your subclasses to implement a method only your superclass can invoke? Do you want to ensure that your subclasses are declaring some private method? Both make no sense to me. – Scharrels Feb 18 '10 at 19:27
  • @Software, that just pushes the problem one step upwards. Why can't we override (or implement) private methods? Looks like a valid usecase for the template-method pattern. – Johannes Schaub - litb Feb 18 '10 at 19:27
  • 4
    @Johannes: What are you talking about? That's exactly what protected methods are for. Private is for things that shouldn't be overridden. – ColinD Feb 18 '10 at 19:39
  • I was in the impression that protected methods are for cases where subclasses need to be able to call the protected method, but not others. But if we only want to implement, but not call a baseclass method, why should we not be allowed to restrict the access to private? At least in C++, making virtual functions private is good style, according to some well-known people. I wonder what the reason of the differing opinions of these two camps is. – Johannes Schaub - litb Feb 18 '10 at 19:46
  • @Johannes: I think what you are describing is essentially the way C# deals with protected members. You can access a protected member in a class only through variables that are statically typed to something that's not higher in the inheritance hierarchy. `new BaseType().ProtectedMethod()` won't work in `DerivedClass` in C#. This makes `protected` members are effectively `private` to other "branches" in the inheritance tree. – Mehrdad Afshari Feb 18 '10 at 19:48
  • @Johannes: Hmm... I suppose I could see something like that being useful, but it's also useful for subclasses to not know about or be able to override private methods in parent classes. In general, I don't think it's a major problem that subclasses can call protected methods of parents themselves. – ColinD Feb 18 '10 at 19:59
  • @Any One- when your concern is ["to keep things as much private as possible"] then why many other method like equals(),toString(),wait(),notify() are there public.they can be protected and they still retain their existing behaviour.where protected cause issues? –  Apr 24 '15 at 06:09
  • syntex `protected void finalize() throws Throwable { }` – roottraveller Jun 14 '17 at 06:53
24

Why is the finalize() method's access modifier is made as protected. Why cant it be public?

It is not public because it shouldn't be invoked by anyone other than the JVM. However, it must be protected so that it can be overridden by subclasses who need to define behavior for it.

If i call it twice in my program, internally what is happening?

You can call it all you want, its just a method after all. However, much like public static void main(String [] args), it has special meaning to the JVM

Will the garbage collector call this again?

Yes

Kevin
  • 30,111
  • 9
  • 76
  • 83
  • But I am still calling that right (meaning I can simply call finalize() method as and when I want inside my object although it does not make any logic)? In that case, they should have designed it in such a way, I should not have been able to call it (from a programmer's viewpoint). – bragboy Feb 18 '10 at 19:23
  • 1
    The point is, you should not call finalize yourself. Ever. It's there for the jvm to clean up(if needed) at garbage collection time in case there is external/native resources that needs to be released in the case the application failed to do so. It's protected so your subclasses can provide an implementation of it if needed. .finalize() is not a replacement for .close/.dispose or other common resource releasing conventions – nos Feb 18 '10 at 20:09
  • 1
    @nos: You should call `super.finalize()` when you override it. – Mehrdad Afshari Feb 18 '10 at 21:01
13
  • finalize is meant to be called by the gc only and as such does not require public access
  • finalize is guaranteed to be called only once by the gc, calling it yourself will break this guarantee, as the gc wont know about it.
  • Any overriding class can make finalize public, which I believe is bad for the above reasons
  • finalize should not contain much code, as any exception thrown by finalize may kill the finalizer thread of the gc.

Rant against finalize()

  • Managing native resources or any resource which requires dispose() or close() to be called may cause hard to find bugs as they will only be released when the jvm runs out of memory, you should release resources manually. Finalize should only be used for debugging resource leaks or for cases where managing resources manually is too much work.
  • finalize will be called in an additional thread of the gc and may cause problems with resource locking and so on.
  • the reference classes like WeakReference and ReferenceQueue are an alternative (rather complex) way to deal with cleanup and may have the same problems as finalize() for native resources.

Beware of errors in the above statements, I'm a bit tired :-)

josefx
  • 15,506
  • 6
  • 38
  • 63
  • 1
    I suspect that the designers of Java were vastly over-optimistic about the utility of `Finalize`; had they not been, something resembling AutoCloseable would have been part of Java 1.0. If the language provided a means of distinguishing between references that encapsulate ownership of resources and those that merely identify resources owned by someone else, I'd posit that 99% of resource cleanup could be automated deterministically, because 99% of entities requiring cleanup will, at all times in their life, have exactly one owner. Not always the same owner, but never zero and never two. – supercat Jan 17 '14 at 21:51
  • While there are a few cases where it makes sense for entities to require cleanup but not have a clear owner, most objects which encapsulate mutable state should have clearly-defined ownership (whether or not they require cleanup) and most objects which require cleanup encapsulate mutable state. Knowing when the last reference to an object goes out of scope is hard; knowing when the one and only owner of an object is done with it is easy. The latter point is when the object should be cleaned up, *regardless of what other references may exist*. – supercat Jan 17 '14 at 21:56
3

Check out this link which discusses it.

Basically, it would make the most sense for it to be private, as it should only be called by the JVM (garbage collector). But in order to allow a subclass to call the parent finalize() method as part of its finalize(), it has to be protected.

(Edit - And just a general caution - use of the finalize() method is generally discouraged as there's no way of ensuring that it will ever be called. Although that doesn't mean that you'll never have occasion to use it - it's just rare.)

froadie
  • 79,995
  • 75
  • 166
  • 235
3

The part about finalize() being called only once applies only to the calls from the GC. You can imagine the object as having a hidden flag "finalize() was called by the GC", and the GC checking that flag to know what to do with the object. The flag is not impacted in any way by your own handmade calls to finalize().

On finalization, read this article from Hans Boehm (who is well-known for his work on garbage collection). This is an eye-opener about finalization; in particular, Boehm explains why finalization is necessarily asynchronous. A corollary is that while finalization is a powerful tool, it is very rarely the right tool for a given job.

Thomas Pornin
  • 72,986
  • 14
  • 147
  • 189
2

It's not public (or default access) because it's meant to be called by the JVM internally when the object is garbage collected - it's not meant to be called by anything else. And it's not private because it's meant to be overridden and you can't override private methods.

If i call it twice in my program, internally what is happening? Will the garbage collector will call this again?

Probably yes, but it's hard to imagine a scenario where this would make any kind of sense - the point of finalize() is to do cleanup when an object is garbage collected. And it doesn't even do that well, so it's really something you should avoid altogether rather than experiment with.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
1

I think the reason why finalize is protected would be that maybe it's overridden by some classes in the JDK, and those overridden methods are called by JVM.

Charles Menguy
  • 40,830
  • 17
  • 95
  • 117
meerut
  • 11
  • 1
1

finalize() is only used by the JVM to clean up resources when the object is collected. It's reasonable for a class to define what actions should be taken on collection, for which it may need to access super.finalize(). It doesn't really make sense for an outside process to call finalize(), since an outside process doesn't have control over when the object is collected.

Steve B.
  • 55,454
  • 12
  • 93
  • 132
  • That said, what would be the answer to my second question. If I call finalize() twice, what will happen? – bragboy Feb 18 '10 at 19:24
  • If the finalize method is implemented properly, it'll cause no harm to call it twice. Object.finalize does nothing,nada,zip by default unless you've overridden it or derive from a class that does override it. If you do call finalize on something that does override it, you might release its resources before you should, and subsequent operations on that object might fail in various ways. – nos Feb 18 '10 at 20:15
  • 'If I call finalize() twice, what will happen?' Why would you do that? You're not supposed to call it even once. The question doesn't arise. – user207421 Feb 19 '10 at 02:37
1

Also, I came to know that finalize() method is called only once. If i call it twice in my program, internally what is happening?

You probably ask this under impression of C++ ~destructors. In java finalize () method doesn't do any magic (like clearing memory). It's supposed to be called by garbage collector. But not vice versa.

I recommend you to read correspondent chapter in Joshua Bloch's "Effective Java". It says that using finalizers is a bad practice and can cause performance and other issues, and there are only several cases when they should be used. The chapter begins with next words:

Finalizers are unpredictable, often dangerous, and generally unnecessary.

Roman
  • 64,384
  • 92
  • 238
  • 332