Question

I new to Java First time I am trying to learn Java . My simple Question is on finalize () method in java.lang.Object. Why I have access to this only protected method in my other class not other protected method .My tutor told me that protected only have scope in its class, same package, and its subclass .Here I read this.

Can someone explain me is there any special case with finalize()method . I have an answer not satisfying why finalize () is protected here My Code is as Follows :

//Creating Package Foo
package Foo;
class A
{
    protected finalize() 
    { 
        System.out.println("This is finalize method of Class A");
    }
}

// Creating Another Pacakage Foo1
package Foo1;
import Foo.*;
class B extends A
{
}
class C extends B
{
}
class D extends C
{
    public void foo() {
        C ob = new C();
        ob = null;
        System.gc(); // Why class A finalize() is getting call
    }
}

Only in case of finalize () it is getting called, not in another case . ask my tutor he refuse to answer he saying you are doing some mistake i will look but he is not replying me .

Please think of I am bew to java . Maybe I am doing some big mistake.

Était-ce utile?

La solution

This works as expected, and I don't think the finalize() method is treated any differently to any other method in Java. What could be considered a bit different is that the finalize() method is normally only called by the JVM Garbage Collector itself, as outlined in the JavaDoc:

Called by the garbage collector on an object when garbage collection determines that there are no more references to the object.

Also note that Josh Bloch strongly cautions against the use of finalizers in Effective Java:

Finalizers are unpredictable, often dangerous, and generally unnecessary. Their use can cause erratic behaviour, poor performance, and portability problems. Finalizers have a few valid uses ... but as a rule of thumb you should avoid finalizers.

Consider the following example, which is similar to yours:

A baseclass with an overriden finalize() method.

public abstract class BaseClass {
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("BaseClass finalisation occured");
    }
}

A sub-class which does not override finalize:

public class SubClass extends BaseClass {
    public void foo() {
        System.out.println("SubClass Foo'd");
    }
}

And a driver class with a basic main method to run everything:

public class Driver {
    public static void main(String[] args) {
        SubClass sc = new SubClass();
        sc.foo();
        sc = null;
        System.gc();        
    }
}

The output we get is the following:

SubClass Foo'd
BaseClass finalisation occured

What happens with Java method lookup (in very simple terms) is that any method is looked for in the current class, and if not the class hierarchy is climbed until the required method is found. In the above example, when the foo() method is called on a SubClass object, the SubClass class contains the method definition so that implementation is used, and the class hierarchy is not climbed any higher. When the finalize() method is called (because a System.gc() has been requested), the method will first be looked for in the SubClass class, but since that does not contain an implementation of finalize() its parent (BaseClass) is searched. BaseClass does contain an implementation of finalize() so that is used, and a line is printed to stdout.

Now consider a sub-sub-class which overrides finalize() again:

public class OverridenSubClass extends SubClass {
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("Overriden finalize called, which calls super's finalize first");
    }
}

And a slightly modified Driver class:

public class Driver {

    public static void main(String[] args) {
        OverridenSubClass sc = new OverridenSubClass();
        sc.foo();
        System.out.println(sc.toString());
        sc = null;
        System.gc();
        System.exit(0);
    }
}

Which produces the following output:

SubClass Foo'd
finalize.OverridenSubClass@7150bd4d
BaseClass finalisation occured
Overriden finalize called, which calls initial finalize first

Hopefully this is as expected. The only interesting things to note here are that:

  1. We don't override toString() in any of our classes so the Object.toString() implementation is used.
  2. The type of variable sc is not what determines the method implementation used - it is the type of the actual object referenced by sc

Autres conseils

My tutor told me that protected only have scope in its class, same package, and its subclass

You misunderstood him. protected provides access to all those scopes, separately. Those conditions don't all have to be satisfied simultaneously.

So, you have classes that inherit from A and can therefore access its protected members.

However, that's all irrelevant. You aren't calling the protected method. You are calling a system method that executes some other code that eventually calls finalize(), and that code has access either by JVM trickery or by virtue of being in the java.lang package, same as Object, which would provide it with access to Object's protected members.

I think its working as expected.After entering into class D and instantiation happens, and then there is no morething to execute and hence finalize() method is getting called. and the answer to your question is

A ^ | B ^ | C ^ | D so D obviously inherits the properties of A so being protected finalize method is accessible to D and hence it is called.

Hope this clarifies your doubt.

finalize is called by the garbage collector when it starts to destroy the instance, because it is not usable anymore (no other objects have a reference to that instance anymore).

The built-in garbage collector is somewhat special, it can call the method, regardless of its access modifier.

The standard rules about access modifiers only apply to your Java classes.

Edit

Subclasses may need to override the finalize to free system resources, even if they're are in a different package. That wouldn't be possible if finalize was a private method. On the other hand it is not wanted that the method is called from outside, because that usually would cause an inconsistent state (like when system ressources are freed or destroyed while the instance is still used), so public is not an option for that method

The following simple example may make it a bit clearer.

package foo;

public class A {

    public void _public() {}

    void _default() {}

    private void _private() {}

    @Override
    protected void finalize() throws Throwable {
        freeSomeResources();  // implementation not shown but it should be clear
    }

}

package bar;

import foo.A;

public class B extends A {

    @Override
    public void _public() {}        // fine

    @Override
    void _default() {}              // compile error -> can't access from other package

    @Override
    private void _private() {}      // compile error -> private method


    @Override                       // fine - subclass may override
    protected void finalize() throws Throwable {
        super.finalize();
    }

}

I don't quite get what is your question: You want to know why garbage collector can call the protected finalize()? – Adrian Shum

@AdrianShum Yes Exactly – Java_begins 1 min ago

If this is your question, then I will try to discuss on it.

First, finalize() is aimed to be a special method that is called by system garbage collector, it won't surprise me if it is a special case that it is handled differently which accessibility is simply ignored.

However, it doesn't necessary mean it is handled specially. I don't know why you come up with a conclusion that it should not happen.

Although you see the method being protected, the finalize() method is in fact declared in Object. That means, if someone have the privilege to access Object#finalize() then it can call that.

Just give an example of normal method.

assume there is a foo package:

package foo;
public class Foo {
    protected void foo() {
        System.out.println("foo");
    }
}

We have a FooRunner in the same package, which can access Foo#foo because they are under same package.

package foo;
public class FooRunner {
    public void runFoo(Foo foo) {
        foo.foo();
    }
}

Then, even if I have another package bar, with a Bar class extending Foo, and overriding foo() method, FooRunner can still take a Bar instance and access its foo()

package bar;
public class Bar extends Foo {
    @Override
    public void foo() {
        System.out.println("bar");
    }
}

// this is still valid
fooRunner.runFoo(new Bar());

Although Bar is defined in another package, FooRunner in package foo can still run the foo() method, indirectly by treating it as a Foo.

In OpenJDK, finalize() is called from native code, using JNI's GetMethodID(). See the comment at the top of java.lang.ref.Finalizer:

/* A native method that invokes an arbitrary object's finalize method is
   required since the finalize method is protected
 */
static native void invokeFinalizeMethod(Object o) throws Throwable;

And the actual call to finalize() from native code in ./jdk/src/share/native/java/lang/ref/Finalizer.c:

JNIEXPORT void JNICALL 
Java_java_lang_ref_Finalizer_invokeFinalizeMethod(JNIEnv *env, jclass clazz,
                                                  jobject ob)
{   
    jclass cls;
    jmethodID mid;

    cls = (*env)->GetObjectClass(env, ob);
    if (cls == NULL) return;
    mid = (*env)->GetMethodID(env, cls, "finalize", "()V");
    if (mid == NULL) return;
    (*env)->CallVoidMethod(env, ob, mid);
}   
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top