Skip to main content

Keep the finalize() Method Protected When Overriding

Critical
maintainabilitysecurity

What is it?

This practice is triggered when the finalize() method is overridden with a public access modifier, which deviates from its intended protection level.

Why apply it?

The Object.finalize() method is meant exclusively for the Garbage Collector to call. Making it public misleads clients into believing they can or should invoke it directly, potentially leading to misuse and creating security vulnerabilities.

How to fix it?

Override the finalize() method with a protected modifier, ensuring it remains inaccessible from outside the class or package.

Examples

Example 1:

Negative

In this negative example, finalize() is overridden with a public modifier, allowing unintended access.

public class MyResource {

@Override
public void finalize() throws Throwable { /* Noncompliant */
try {
// Resource cleanup logic
System.out.println("Cleaning up resources");
} finally {
super.finalize();
}
}
}

Example 2:

Positive

In this positive example, finalize() is overridden with a protected modifier, maintaining its restricted access.

public class MyResource {

@Override
protected void finalize() throws Throwable { /* Compliant */
try {
// Resource cleanup logic
System.out.println("Cleaning up resources");
} finally {
super.finalize();
}
}
}

Negative

The finalize() method in this example is incorrectly public, offering unauthorized public access.

public class CacheManager {

@Override
public void finalize() throws Throwable { /* Noncompliant */
try {
// Perform cleanup of cache
System.out.println("Finalizing cache cleanup");
} finally {
super.finalize();
}
}
}

Example 3:

Positive

Here, finalize() is correctly overridden with a protected access level to prevent external access.

public class CacheManager {

@Override
protected void finalize() throws Throwable { /* Compliant */
try {
// Perform cleanup of cache
System.out.println("Finalizing cache cleanup");
} finally {
super.finalize();
}
}
}